manager: weekly wiew for agendas & resources (#33404)
This commit is contained in:
parent
a9236fac0d
commit
863dc6ce70
|
@ -12,7 +12,12 @@ class Migration(migrations.Migration):
|
|||
model_name='agenda',
|
||||
name='default_view',
|
||||
field=models.CharField(
|
||||
choices=[('day', 'Day view'), ('month', 'Month view'), ('open_events', 'Open events')],
|
||||
choices=[
|
||||
('day', 'Day view'),
|
||||
('week', 'Week view'),
|
||||
('month', 'Month view'),
|
||||
('open_events', 'Open events'),
|
||||
],
|
||||
max_length=20,
|
||||
verbose_name='Default view',
|
||||
),
|
||||
|
|
|
@ -70,6 +70,7 @@ AGENDA_KINDS = (
|
|||
|
||||
AGENDA_VIEWS = (
|
||||
('day', _('Day view')),
|
||||
('week', _('Week view')),
|
||||
('month', _('Month view')),
|
||||
('open_events', _('Open events')),
|
||||
)
|
||||
|
|
|
@ -10,8 +10,10 @@ $(function() {
|
|||
$('.date-picker button').on('click', function() {
|
||||
if ($('[name=day]').val()) {
|
||||
window.location = '../../../' + $('[name=year]').val() + '/' + $('[name=month]').val() + '/' + $('[name=day]').val() + '/';
|
||||
} else {
|
||||
} else if ($('[name=month]').val()) {
|
||||
window.location = '../../' + $('[name=year]').val() + '/' + $('[name=month]').val() + '/';
|
||||
} else {
|
||||
window.location = '../../../' + $('[name=year]').val() + '/week/' + $('[name=week]').val() + '/';
|
||||
}
|
||||
return false;
|
||||
});
|
||||
|
|
|
@ -0,0 +1,32 @@
|
|||
{% extends "chrono/manager_agenda_view.html" %}
|
||||
{% load i18n %}
|
||||
|
||||
{% block bodyargs %}class="weekview"{% endblock %}
|
||||
|
||||
{% block breadcrumb %}
|
||||
{{ block.super }}
|
||||
<a>{{ view.date|date:"F Y" }}</a>
|
||||
{% endblock %}
|
||||
|
||||
{% block appbar %}
|
||||
<h2>
|
||||
<a href="{{ view.get_previous_week_url }}">←</a>
|
||||
<span class="date-title">{{ view.date|date:_("Y \w\e\e\k W") }}</span>
|
||||
{% with selected_week=view.date|date:"W" selected_year=view.date|date:"Y" %}
|
||||
<div class="date-picker" style="display: none">
|
||||
<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>
|
||||
<select name="year">{% for year in view.get_years %}<option value="{{ year }}" {% if selected_year == year %}selected{% endif %}>{{ year }}</option>{% endfor %}</select>
|
||||
<button>{% trans 'Set Date' %}</button>
|
||||
</div>
|
||||
{% endwith %}
|
||||
<a href="{{ view.get_next_week_url }}">→</a>
|
||||
</h2>
|
||||
<span class="actions">
|
||||
{% block actions %}
|
||||
{% if user_can_manage %}
|
||||
<a href="{{ agenda.get_settings_url }}">{% trans 'Settings' %}</a>
|
||||
{% endif %}
|
||||
<a href="" onclick="window.print()">{% trans 'Print' %}</a>
|
||||
{% endblock %}
|
||||
</span>
|
||||
{% endblock %}
|
|
@ -11,6 +11,7 @@
|
|||
{{ block.super }}
|
||||
<a href="{% url 'chrono-manager-agenda-open-events-view' pk=agenda.pk %}">{% trans 'Open events' %}</a>
|
||||
<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>
|
||||
<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>
|
||||
{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
|
|
|
@ -11,6 +11,7 @@
|
|||
</ul>
|
||||
{{ block.super }}
|
||||
<a href="{% url 'chrono-manager-agenda-open-events-view' pk=agenda.pk %}">{% trans 'Open events' %}</a>
|
||||
<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>
|
||||
<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>
|
||||
{% endblock %}
|
||||
|
||||
|
|
|
@ -0,0 +1,44 @@
|
|||
{% extends "chrono/manager_agenda_week_view.html" %}
|
||||
{% load i18n %}
|
||||
|
||||
{% block actions %}
|
||||
<a class="extra-actions-menu-opener"></a>
|
||||
<ul class="extra-actions-menu">
|
||||
<li><a href="{% url 'chrono-manager-event-cancellation-report-list' pk=agenda.pk %}">{% trans 'Cancellation error reports' %}</a></li>
|
||||
{% if agenda.subscriptions.exists %}
|
||||
<li><a href="{% url 'chrono-manager-events-timesheet' pk=agenda.pk %}">{% trans 'Timesheet' %}</a></li>
|
||||
{% endif %}
|
||||
</ul>
|
||||
{{ block.super }}
|
||||
<a href="{% url 'chrono-manager-agenda-open-events-view' pk=agenda.pk %}">{% trans 'Open events' %}</a>
|
||||
<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>
|
||||
<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>
|
||||
{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<div class="section">
|
||||
<h3>{% trans "Events" %}</h3>
|
||||
{% include 'chrono/manager_event_cancellation_report_notice.html' %}
|
||||
<div>
|
||||
{% if object_list %}
|
||||
<ul class="objects-list single-links">
|
||||
{% for object in object_list %}
|
||||
{% if object.is_exception %}
|
||||
<li><a class="disabled">{% trans "Exception:"%} {{ object }}</a></li>
|
||||
{% else %}
|
||||
{% include 'chrono/manager_agenda_event_fragment.html' with event=object %}
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
</ul>
|
||||
{% include "gadjo/pagination.html" %}
|
||||
{% else %}
|
||||
<div class="big-msg-info">
|
||||
{% blocktrans trimmed %}
|
||||
This week doesn't have any event configured.
|
||||
{% endblocktrans %}
|
||||
</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{% endblock %}
|
|
@ -4,6 +4,7 @@
|
|||
{% block actions %}
|
||||
{{ block.super }}
|
||||
<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>
|
||||
<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>
|
||||
{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
|
|
|
@ -3,64 +3,10 @@
|
|||
|
||||
{% block actions %}
|
||||
{{ block.super }}
|
||||
<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>
|
||||
<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>
|
||||
{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
|
||||
{% for week_days in view.get_timetable_infos %}
|
||||
{% if forloop.first %}
|
||||
<table class="agenda-table month-view {% if single_desk %}single-desk{% endif %}">
|
||||
<tbody>
|
||||
{% endif %}
|
||||
<tr>
|
||||
<th></th>
|
||||
{% for day in week_days.days %}
|
||||
<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>
|
||||
{% endfor %}
|
||||
</tr>
|
||||
{% for hour in week_days.periods %}
|
||||
<tr class="{% cycle 'odd' 'even' %}">
|
||||
<th class="hour">{{ hour|date:"TIME_FORMAT" }}</th>
|
||||
{% for day in week_days.days %}
|
||||
<td class="{% if day.other_month %}other-month{% endif %} {% if day.today %}today{% endif %}">
|
||||
{% if forloop.parentloop.first %}
|
||||
{% for slot in day.infos.opening_hours %}
|
||||
<div class="opening-hours" style="height:{{ slot.css_height|stringformat:".1f" }}%;top:{{ slot.css_top|stringformat:".1f" }}%;width:{{ slot.css_width|stringformat:".1f" }}%;left:{{ slot.css_left|stringformat:".1f" }}%;"></div>
|
||||
{% endfor %}
|
||||
|
||||
{% for slot in day.infos.exceptions %}
|
||||
<div class="exception-hours" style="height:{{ slot.css_height|stringformat:".1f" }}%;top:{{ slot.css_top|stringformat:".1f" }}%;width:{{ slot.css_width|stringformat:".1f" }}%;left:{{ slot.css_left|stringformat:".1f" }}%;" {% if slot.label %}title="{{ slot.label }}"{% endif %}></div>
|
||||
{% endfor %}
|
||||
|
||||
{% for slot in day.infos.booked_slots %}
|
||||
<div class="booking{% 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" }}%;">
|
||||
<span class="start-time">{{slot.booking.event.start_datetime|date:"TIME_FORMAT"}}</span>
|
||||
<a {% if slot.booking.get_backoffice_url %}href="{{slot.booking.get_backoffice_url}}"{% endif %}>{{ slot.booking.get_user_block }}</a>
|
||||
<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>
|
||||
{% if not single_desk %}<span class="desk">{{ slot.desk }}</span>{% endif %}
|
||||
{% if slot.booking.color %}<span class="booking-color-label booking-bg-color-{{ slot.booking.color.index }}">{{ slot.booking.color }}</span>{% endif %}
|
||||
</div>
|
||||
{% endfor %}
|
||||
{% endif %}
|
||||
</td>
|
||||
{% endfor %}
|
||||
</tr>
|
||||
{% endfor %}
|
||||
{% resetcycle %}
|
||||
{% if forloop.last %}
|
||||
</tbody>
|
||||
</table>
|
||||
{% endif %}
|
||||
|
||||
{% empty %}
|
||||
<div class="closed-for-the-day">
|
||||
<p>{% trans "No opening hours this month." %}</p>
|
||||
</div>
|
||||
{% endfor %}
|
||||
|
||||
{% if booking_colors %}
|
||||
{% include "chrono/booking_color_legend.html" with colors=booking_colors %}
|
||||
{% endif %}
|
||||
|
||||
{% include "chrono/manager_meetings_agenda_week_timetable_fragment.html" %}
|
||||
{% endblock %}
|
||||
|
|
|
@ -0,0 +1,59 @@
|
|||
{% load i18n %}
|
||||
{% for week_days in view.get_timetable_infos %}
|
||||
{% if forloop.first %}
|
||||
<table class="agenda-table {{ kind }}-view {% if kind == 'week' %}hourspan-{{ hour_span }}{% endif %} {% if single_desk %}single-desk{% endif %}">
|
||||
<tbody>
|
||||
{% endif %}
|
||||
<tr>
|
||||
<th></th>
|
||||
{% for day in week_days.days %}
|
||||
<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>
|
||||
{% endfor %}
|
||||
</tr>
|
||||
{% for hour in week_days.periods %}
|
||||
<tr class="{% cycle 'odd' 'even' %}">
|
||||
<th class="hour">{{ hour|date:"TIME_FORMAT" }}</th>
|
||||
{% for day in week_days.days %}
|
||||
<td class="{% if kind == 'month' and day.other_month %}other-month{% endif %} {% if day.today %}today{% endif %}">
|
||||
{% if forloop.parentloop.first %}
|
||||
{% for slot in day.infos.opening_hours %}
|
||||
<div class="opening-hours" style="height:{{ slot.css_height|stringformat:".1f" }}%;top:{{ slot.css_top|stringformat:".1f" }}%;width:{{ slot.css_width|stringformat:".1f" }}%;left:{{ slot.css_left|stringformat:".1f" }}%;"></div>
|
||||
{% endfor %}
|
||||
|
||||
{% for slot in day.infos.exceptions %}
|
||||
<div class="exception-hours" style="height:{{ slot.css_height|stringformat:".1f" }}%;top:{{ slot.css_top|stringformat:".1f" }}%;width:{{ slot.css_width|stringformat:".1f" }}%;left:{{ slot.css_left|stringformat:".1f" }}%;" {% if slot.label %}title="{{ slot.label }}"{% endif %}></div>
|
||||
{% endfor %}
|
||||
|
||||
{% for slot in day.infos.booked_slots %}
|
||||
<div class="booking{% 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" }}%;">
|
||||
<span class="start-time">{{slot.booking.event.start_datetime|date:"TIME_FORMAT"}}</span>
|
||||
<a {% if slot.booking.get_backoffice_url %}href="{{slot.booking.get_backoffice_url}}"{% endif %}>{{ slot.booking.get_user_block }}</a>
|
||||
<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>
|
||||
{% if not single_desk %}<span class="desk">{{ slot.desk }}</span>{% endif %}
|
||||
{% if slot.booking.color %}<span class="booking-color-label booking-bg-color-{{ slot.booking.color.index }}">{{ slot.booking.color }}</span>{% endif %}
|
||||
</div>
|
||||
{% endfor %}
|
||||
{% endif %}
|
||||
</td>
|
||||
{% endfor %}
|
||||
</tr>
|
||||
{% endfor %}
|
||||
{% resetcycle %}
|
||||
{% if forloop.last %}
|
||||
</tbody>
|
||||
</table>
|
||||
{% endif %}
|
||||
|
||||
{% empty %}
|
||||
<div class="closed-for-the-day">
|
||||
{% if kind == 'month' %}
|
||||
<p>{% trans "No opening hours this month." %}</p>
|
||||
{% else %}
|
||||
<p>{% trans "No opening hours this week." %}</p>
|
||||
{% endif %}
|
||||
</div>
|
||||
{% endfor %}
|
||||
|
||||
{% if booking_colors %}
|
||||
{% include "chrono/booking_color_legend.html" with colors=booking_colors %}
|
||||
{% endif %}
|
|
@ -0,0 +1,12 @@
|
|||
{% extends "chrono/manager_agenda_week_view.html" %}
|
||||
{% load i18n %}
|
||||
|
||||
{% block actions %}
|
||||
{{ block.super }}
|
||||
<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>
|
||||
<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>
|
||||
{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
{% include "chrono/manager_meetings_agenda_week_timetable_fragment.html" %}
|
||||
{% endblock %}
|
|
@ -23,6 +23,7 @@
|
|||
{% endblock %}
|
||||
{% block appbar-extras %}
|
||||
<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>
|
||||
<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>
|
||||
{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
|
|
|
@ -22,8 +22,10 @@
|
|||
{% endif %}
|
||||
{% now "Y" as today_year %}
|
||||
{% now "n" as today_month %}
|
||||
{% now "W" as today_week %}
|
||||
{% now "j" as today_day %}
|
||||
<a href="{% url 'chrono-manager-resource-month-view' pk=resource.pk year=today_year month=today_month %}">{% trans 'Month view' %}</a>
|
||||
<a href="{% url 'chrono-manager-resource-week-view' pk=resource.pk year=today_year week=today_week %}">{% trans 'Week view' %}</a>
|
||||
<a href="{% url 'chrono-manager-resource-day-view' pk=resource.pk year=today_year month=today_month day=today_day %}">{% trans 'Day view' %}</a>
|
||||
{% endblock %}
|
||||
</span>
|
||||
|
|
|
@ -23,48 +23,10 @@
|
|||
</h2>
|
||||
{% endblock %}
|
||||
{% block appbar-extras %}
|
||||
<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>
|
||||
<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>
|
||||
<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>
|
||||
{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
|
||||
{% for week_days in view.get_timetable_infos %}
|
||||
|
||||
{% if forloop.first %}
|
||||
<table class="agenda-table month-view single-desk">
|
||||
<tbody>
|
||||
{% endif %}
|
||||
<tr>
|
||||
<th></th>
|
||||
{% for day in week_days.days %}
|
||||
<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>
|
||||
{% endfor %}
|
||||
</tr>
|
||||
{% for hour in week_days.periods %}
|
||||
<tr class="{% cycle 'odd' 'even' %}">
|
||||
<th class="hour">{{ hour|date:"TIME_FORMAT" }}</th>
|
||||
{% for day in week_days.days %}
|
||||
<td class="{% if day.other_month %}other-month{% endif %} {% if day.today %}today{% endif %}">
|
||||
{% if forloop.parentloop.first %}
|
||||
{% for slot in day.infos.booked_slots %}
|
||||
<div class="booking" style="height:{{ slot.css_height|stringformat:".1f" }}%;min-height:{{ slot.css_height|stringformat:".1f" }}%;top:{{ slot.css_top|stringformat:".1f" }}%">
|
||||
<span class="start-time">{{ slot.booking.event.start_datetime|date:"TIME_FORMAT" }}</span>
|
||||
<a {% if slot.booking.get_backoffice_url %}href="{{ slot.booking.get_backoffice_url }}"{% endif %}>{{ slot.booking.get_user_block }}</a>
|
||||
</div>
|
||||
{% endfor %}
|
||||
{% endif %}
|
||||
</td>
|
||||
{% endfor %}
|
||||
</tr>
|
||||
{% endfor %}
|
||||
{% if forloop.last %}
|
||||
</tbody>
|
||||
</table>
|
||||
{% endif %}
|
||||
{% empty %}
|
||||
<div class="closed-for-the-day">
|
||||
<p>{% trans "No bookings this month." %}</p>
|
||||
</div>
|
||||
{% endfor %}
|
||||
|
||||
{% include "chrono/manager_resource_week_timetable_fragment.html" %}
|
||||
{% endblock %}
|
||||
|
|
|
@ -0,0 +1,43 @@
|
|||
{% load i18n %}
|
||||
{% for week_days in view.get_timetable_infos %}
|
||||
|
||||
{% if forloop.first %}
|
||||
<table class="agenda-table {{ kind }}-view {% if kind == 'week' %}hourspan-{{ hour_span }}{% endif %} single-desk">
|
||||
<tbody>
|
||||
{% endif %}
|
||||
<tr>
|
||||
<th></th>
|
||||
{% for day in week_days.days %}
|
||||
<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>
|
||||
{% endfor %}
|
||||
</tr>
|
||||
{% for hour in week_days.periods %}
|
||||
<tr class="{% cycle 'odd' 'even' %}">
|
||||
<th class="hour">{{ hour|date:"TIME_FORMAT" }}</th>
|
||||
{% for day in week_days.days %}
|
||||
<td class="{% if kind == 'month' and day.other_month %}other-month{% endif %} {% if day.today %}today{% endif %}">
|
||||
{% if forloop.parentloop.first %}
|
||||
{% for slot in day.infos.booked_slots %}
|
||||
<div class="booking" style="height:{{ slot.css_height|stringformat:".1f" }}%;min-height:{{ slot.css_height|stringformat:".1f" }}%;top:{{ slot.css_top|stringformat:".1f" }}%">
|
||||
<span class="start-time">{{ slot.booking.event.start_datetime|date:"TIME_FORMAT" }}</span>
|
||||
<a {% if slot.booking.get_backoffice_url %}href="{{ slot.booking.get_backoffice_url }}"{% endif %}>{{ slot.booking.get_user_block }}</a>
|
||||
</div>
|
||||
{% endfor %}
|
||||
{% endif %}
|
||||
</td>
|
||||
{% endfor %}
|
||||
</tr>
|
||||
{% endfor %}
|
||||
{% if forloop.last %}
|
||||
</tbody>
|
||||
</table>
|
||||
{% endif %}
|
||||
{% empty %}
|
||||
<div class="closed-for-the-day">
|
||||
{% if kind == 'month' %}
|
||||
<p>{% trans "No bookings this month." %}</p>
|
||||
{% else %}
|
||||
<p>{% trans "No bookings this week." %}</p>
|
||||
{% endif %}
|
||||
</div>
|
||||
{% endfor %}
|
|
@ -0,0 +1,32 @@
|
|||
{% extends "chrono/manager_resource_detail.html" %}
|
||||
{% load i18n %}
|
||||
|
||||
{% block bodyargs %}class="weekview"{% endblock %}
|
||||
|
||||
{% block breadcrumb %}
|
||||
{{ block.super }}
|
||||
<a>{{ view.date|date:"F Y" }}</a>
|
||||
{% endblock %}
|
||||
|
||||
{% block appbar-title %}
|
||||
<h2>
|
||||
<a href="{{ view.get_previous_week_url }}">←</a>
|
||||
<span class="date-title">{{ view.date|date:_("Y \w\e\e\k W") }}</span>
|
||||
{% with selected_week=view.date|date:"W" selected_year=view.date|date:"Y" %}
|
||||
<div class="date-picker" style="display: none">
|
||||
<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>
|
||||
<select name="year">{% for year in view.get_years %}<option value="{{ year }}" {% if selected_year == year %}selected{% endif %}>{{ year }}</option>{% endfor %}</select>
|
||||
<button>{% trans 'Set Date' %}</button>
|
||||
</div>
|
||||
{% endwith %}
|
||||
<a href="{{ view.get_next_week_url }}">→</a>
|
||||
</h2>
|
||||
{% endblock %}
|
||||
{% block appbar-extras %}
|
||||
<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>
|
||||
<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>
|
||||
{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
{% include "chrono/manager_resource_week_timetable_fragment.html" %}
|
||||
{% endblock %}
|
|
@ -73,6 +73,11 @@ urlpatterns = [
|
|||
views.resource_monthly_view,
|
||||
name='chrono-manager-resource-month-view',
|
||||
),
|
||||
re_path(
|
||||
r'^resource/(?P<pk>\d+)/(?P<year>[0-9]{4})/week/(?P<week>[0-9]+)/$',
|
||||
views.resource_weekly_view,
|
||||
name='chrono-manager-resource-week-view',
|
||||
),
|
||||
re_path(
|
||||
r'^resource/(?P<pk>\d+)/(?P<year>[0-9]{4})/(?P<month>[0-9]+)/(?P<day>[0-9]+)/$',
|
||||
views.resource_day_view,
|
||||
|
@ -107,6 +112,16 @@ urlpatterns = [
|
|||
views.agenda_monthly_view,
|
||||
name='chrono-manager-agenda-month-view',
|
||||
),
|
||||
path(
|
||||
'agendas/<int:pk>/week/',
|
||||
views.agenda_week_redirect_view,
|
||||
name='chrono-manager-agenda-week-redirect-view',
|
||||
),
|
||||
re_path(
|
||||
r'^agendas/(?P<pk>\d+)/(?P<year>[0-9]{4})/week/(?P<week>[0-9]+)/$',
|
||||
views.agenda_weekly_view,
|
||||
name='chrono-manager-agenda-week-view',
|
||||
),
|
||||
path(
|
||||
'agendas/<int:pk>/day/',
|
||||
views.agenda_day_redirect_view,
|
||||
|
|
|
@ -57,6 +57,7 @@ from django.views.generic import (
|
|||
TemplateView,
|
||||
UpdateView,
|
||||
View,
|
||||
WeekArchiveView,
|
||||
)
|
||||
from django.views.generic.dates import MonthMixin, YearMixin
|
||||
from weasyprint import HTML
|
||||
|
@ -250,6 +251,9 @@ class DateMixin:
|
|||
def get_months(self):
|
||||
return [(str(x), MONTHS[x]) for x in range(1, 13)]
|
||||
|
||||
def get_weeks(self):
|
||||
return [(str(x), _('Week %s') % x) for x in range(1, 53)]
|
||||
|
||||
def get_years(self):
|
||||
year = now().year
|
||||
return [str(x) for x in range(year - 1, year + 5)]
|
||||
|
@ -384,28 +388,7 @@ class ResourceDayView(DateMixin, DayArchiveView):
|
|||
resource_day_view = ResourceDayView.as_view()
|
||||
|
||||
|
||||
class ResourceMonthView(DateMixin, MonthArchiveView):
|
||||
template_name = 'chrono/manager_resource_month_view.html'
|
||||
model = Event
|
||||
month_format = '%m'
|
||||
date_field = 'start_datetime'
|
||||
allow_empty = True
|
||||
allow_future = True
|
||||
|
||||
def dispatch(self, request, *args, **kwargs):
|
||||
self.resource = get_object_or_404(Resource, pk=kwargs['pk'])
|
||||
if not self.resource.can_be_viewed(request.user):
|
||||
raise PermissionDenied()
|
||||
try:
|
||||
self.date = make_aware(
|
||||
datetime.datetime.strptime(
|
||||
'%s-%s-%s 06:00' % (self.get_year(), self.get_month(), 1), '%Y-%m-%d %H:%M'
|
||||
)
|
||||
)
|
||||
except ValueError:
|
||||
raise Http404
|
||||
return super().dispatch(request, *args, **kwargs)
|
||||
|
||||
class ResourceWeekMonthMixin:
|
||||
def get_queryset(self):
|
||||
queryset = (
|
||||
self.resource.event_set.all()
|
||||
|
@ -418,23 +401,19 @@ class ResourceMonthView(DateMixin, MonthArchiveView):
|
|||
context = super().get_context_data(**kwargs)
|
||||
|
||||
context['resource'] = self.resource
|
||||
context['kind'] = self.kind
|
||||
context['hour_span'] = 1
|
||||
durations = MeetingType.objects.filter(agenda__resources=self.resource).values_list(
|
||||
'duration', flat=True
|
||||
)
|
||||
if durations:
|
||||
gcd = durations[0]
|
||||
for duration in durations[1:]:
|
||||
gcd = math.gcd(duration, gcd)
|
||||
context['hour_span'] = max(60 // gcd, 1)
|
||||
|
||||
return context
|
||||
|
||||
def get_previous_month_url(self):
|
||||
previous_month = self.get_previous_month(self.date.date())
|
||||
return reverse(
|
||||
'chrono-manager-resource-month-view',
|
||||
kwargs={'pk': self.resource.pk, 'year': previous_month.year, 'month': previous_month.month},
|
||||
)
|
||||
|
||||
def get_next_month_url(self):
|
||||
next_month = self.get_next_month(self.date.date())
|
||||
return reverse(
|
||||
'chrono-manager-resource-month-view',
|
||||
kwargs={'pk': self.resource.pk, 'year': next_month.year, 'month': next_month.month},
|
||||
)
|
||||
|
||||
def get_timetable_infos(self):
|
||||
interval = datetime.timedelta(minutes=60)
|
||||
|
||||
|
@ -469,18 +448,20 @@ class ResourceMonthView(DateMixin, MonthArchiveView):
|
|||
hide_weekend = hide_weekend_timeperiod and hide_weekend_event
|
||||
|
||||
# avoid displaying empty first week
|
||||
first_week_offset = int(
|
||||
(hide_sunday and self.date.weekday() == 6) or (hide_weekend and self.date.weekday() == 5)
|
||||
)
|
||||
|
||||
first_week_offset = 0
|
||||
first_week_number = self.date.isocalendar()[1]
|
||||
if first_week_number >= 52:
|
||||
first_week_number = 0
|
||||
last_month_day = self.get_next_month(self.date.date()) - datetime.timedelta(days=1)
|
||||
last_week_number = last_month_day.isocalendar()[1]
|
||||
last_week_number = first_week_number
|
||||
if self.kind == 'month':
|
||||
first_week_offset = int(
|
||||
(hide_sunday and self.date.weekday() == 6) or (hide_weekend and self.date.weekday() == 5)
|
||||
)
|
||||
if first_week_number >= 52:
|
||||
first_week_number = 0
|
||||
last_day = self.get_next(self.date.date()) - datetime.timedelta(days=1)
|
||||
last_week_number = last_day.isocalendar()[1]
|
||||
|
||||
if last_week_number < first_week_number: # new year
|
||||
last_week_number = 53
|
||||
if last_week_number < first_week_number: # new year
|
||||
last_week_number = 53
|
||||
|
||||
for week_number in range(first_week_number + first_week_offset, last_week_number + 1):
|
||||
yield self.get_week_timetable_infos(
|
||||
|
@ -528,8 +509,8 @@ class ResourceMonthView(DateMixin, MonthArchiveView):
|
|||
# until the end of the last hour.
|
||||
max_date += datetime.timedelta(hours=1)
|
||||
|
||||
# compute booking and opening hours only for current month
|
||||
if self.date.month != day.month:
|
||||
# compute booking and opening hours only for current month/week
|
||||
if self.kind == 'month' and timetable['other_month']:
|
||||
return timetable
|
||||
|
||||
while period <= max_date:
|
||||
|
@ -552,6 +533,92 @@ class ResourceMonthView(DateMixin, MonthArchiveView):
|
|||
return timetable
|
||||
|
||||
|
||||
class ResourceWeekView(ResourceWeekMonthMixin, DateMixin, WeekArchiveView):
|
||||
template_name = 'chrono/manager_resource_week_view.html'
|
||||
model = Event
|
||||
week_format = '%W'
|
||||
date_field = 'start_datetime'
|
||||
allow_empty = True
|
||||
allow_future = True
|
||||
kind = 'week'
|
||||
|
||||
def dispatch(self, request, *args, **kwargs):
|
||||
self.resource = get_object_or_404(Resource, pk=kwargs['pk'])
|
||||
if not self.resource.can_be_viewed(request.user):
|
||||
raise PermissionDenied()
|
||||
try:
|
||||
date = datetime.datetime.strptime('%s-W%s-1' % (self.get_year(), self.get_week()), "%Y-W%W-%w")
|
||||
self.date = make_aware(
|
||||
datetime.datetime.strptime(
|
||||
'%s-%s-%s 06:00' % (self.get_year(), date.month, date.day), '%Y-%m-%d %H:%M'
|
||||
)
|
||||
)
|
||||
except ValueError:
|
||||
raise Http404
|
||||
return super().dispatch(request, *args, **kwargs)
|
||||
|
||||
def get_previous_week_url(self):
|
||||
previous_week = self.get_previous_week(self.date.date())
|
||||
return reverse(
|
||||
'chrono-manager-resource-week-view',
|
||||
kwargs={'pk': self.resource.pk, 'year': previous_week.year, 'week': previous_week.strftime('%W')},
|
||||
)
|
||||
|
||||
def get_next_week_url(self):
|
||||
next_week = self.get_next_week(self.date.date())
|
||||
return reverse(
|
||||
'chrono-manager-resource-week-view',
|
||||
kwargs={'pk': self.resource.pk, 'year': next_week.year, 'week': next_week.strftime('%W')},
|
||||
)
|
||||
|
||||
def get_next(self, date):
|
||||
return self.get_next_week(date)
|
||||
|
||||
|
||||
resource_weekly_view = ResourceWeekView.as_view()
|
||||
|
||||
|
||||
class ResourceMonthView(ResourceWeekMonthMixin, DateMixin, MonthArchiveView):
|
||||
template_name = 'chrono/manager_resource_month_view.html'
|
||||
model = Event
|
||||
month_format = '%m'
|
||||
date_field = 'start_datetime'
|
||||
allow_empty = True
|
||||
allow_future = True
|
||||
kind = 'month'
|
||||
|
||||
def dispatch(self, request, *args, **kwargs):
|
||||
self.resource = get_object_or_404(Resource, pk=kwargs['pk'])
|
||||
if not self.resource.can_be_viewed(request.user):
|
||||
raise PermissionDenied()
|
||||
try:
|
||||
self.date = make_aware(
|
||||
datetime.datetime.strptime(
|
||||
'%s-%s-%s 06:00' % (self.get_year(), self.get_month(), 1), '%Y-%m-%d %H:%M'
|
||||
)
|
||||
)
|
||||
except ValueError:
|
||||
raise Http404
|
||||
return super().dispatch(request, *args, **kwargs)
|
||||
|
||||
def get_previous_month_url(self):
|
||||
previous_month = self.get_previous_month(self.date.date())
|
||||
return reverse(
|
||||
'chrono-manager-resource-month-view',
|
||||
kwargs={'pk': self.resource.pk, 'year': previous_month.year, 'month': previous_month.month},
|
||||
)
|
||||
|
||||
def get_next_month_url(self):
|
||||
next_month = self.get_next_month(self.date.date())
|
||||
return reverse(
|
||||
'chrono-manager-resource-month-view',
|
||||
kwargs={'pk': self.resource.pk, 'year': next_month.year, 'month': next_month.month},
|
||||
)
|
||||
|
||||
def get_next(self, date):
|
||||
return self.get_next_month(date)
|
||||
|
||||
|
||||
resource_monthly_view = ResourceMonthView.as_view()
|
||||
|
||||
|
||||
|
@ -1082,6 +1149,9 @@ class AgendaView(ViewableAgendaMixin, View):
|
|||
if self.agenda.default_view == 'day':
|
||||
return redirect('chrono-manager-agenda-day-redirect-view', pk=self.agenda.pk)
|
||||
|
||||
if self.agenda.default_view == 'week':
|
||||
return redirect('chrono-manager-agenda-week-redirect-view', pk=self.agenda.pk)
|
||||
|
||||
if self.agenda.default_view == 'month':
|
||||
return redirect('chrono-manager-agenda-month-redirect-view', pk=self.agenda.pk)
|
||||
|
||||
|
@ -1114,6 +1184,17 @@ class AgendaMonthRedirectView(ViewableAgendaMixin, View):
|
|||
agenda_month_redirect_view = AgendaMonthRedirectView.as_view()
|
||||
|
||||
|
||||
class AgendaWeekRedirectView(AgendaMonthRedirectView):
|
||||
def get(self, request, *args, **kwargs):
|
||||
day = self.get_day()
|
||||
return redirect(
|
||||
'chrono-manager-agenda-week-view', pk=self.agenda.pk, year=day.year, week=day.strftime('%W')
|
||||
)
|
||||
|
||||
|
||||
agenda_week_redirect_view = AgendaWeekRedirectView.as_view()
|
||||
|
||||
|
||||
class AgendaDayRedirectView(AgendaMonthRedirectView):
|
||||
def get(self, request, *args, **kwargs):
|
||||
day = self.get_day()
|
||||
|
@ -1128,6 +1209,7 @@ agenda_day_redirect_view = AgendaDayRedirectView.as_view()
|
|||
class AgendaDateView(DateMixin, ViewableAgendaMixin):
|
||||
model = Event
|
||||
month_format = '%m'
|
||||
week_format = '%W'
|
||||
date_field = 'start_datetime'
|
||||
allow_empty = True
|
||||
allow_future = True
|
||||
|
@ -1333,7 +1415,7 @@ class AgendaDayView(AgendaDateView, DayArchiveView):
|
|||
agenda_day_view = AgendaDayView.as_view()
|
||||
|
||||
|
||||
class AgendaMonthView(AgendaDateView, MonthArchiveView):
|
||||
class AgendaWeekMonthMixin:
|
||||
def get_queryset(self):
|
||||
qs = super().get_queryset()
|
||||
if self.agenda.kind != 'events':
|
||||
|
@ -1343,9 +1425,9 @@ class AgendaMonthView(AgendaDateView, MonthArchiveView):
|
|||
def get_dated_items(self):
|
||||
date_list, object_list, extra_context = super().get_dated_items()
|
||||
if self.agenda.kind == 'events':
|
||||
min_start = make_aware(datetime.datetime.combine(extra_context['month'], datetime.time(0, 0)))
|
||||
min_start = make_aware(datetime.datetime.combine(extra_context[self.kind], datetime.time(0, 0)))
|
||||
max_start = make_aware(
|
||||
datetime.datetime.combine(extra_context['next_month'], datetime.time(0, 0))
|
||||
datetime.datetime.combine(extra_context['next_%s' % self.kind], datetime.time(0, 0))
|
||||
)
|
||||
exceptions = TimePeriodException.objects.filter(
|
||||
desk__agenda=self.agenda, start_datetime__gte=min_start, end_datetime__lt=max_start
|
||||
|
@ -1353,11 +1435,6 @@ class AgendaMonthView(AgendaDateView, MonthArchiveView):
|
|||
object_list = sorted(itertools.chain(object_list, exceptions), key=lambda x: x.start_datetime)
|
||||
return date_list, object_list, extra_context
|
||||
|
||||
def get_template_names(self):
|
||||
if self.agenda.kind == 'virtual':
|
||||
return ['chrono/manager_meetings_agenda_month_view.html']
|
||||
return ['chrono/manager_%s_agenda_month_view.html' % self.agenda.kind]
|
||||
|
||||
def get_context_data(self, **kwargs):
|
||||
context = super().get_context_data(**kwargs)
|
||||
if self.agenda.kind == 'events':
|
||||
|
@ -1367,25 +1444,9 @@ class AgendaMonthView(AgendaDateView, MonthArchiveView):
|
|||
).all()
|
||||
else:
|
||||
context['single_desk'] = bool(len(self.agenda.prefetched_desks) == 1)
|
||||
context['kind'] = self.kind
|
||||
return context
|
||||
|
||||
def get_previous_month_url(self):
|
||||
previous_month = self.get_previous_month(self.date.date())
|
||||
return reverse(
|
||||
'chrono-manager-agenda-month-view',
|
||||
kwargs={'pk': self.agenda.id, 'year': previous_month.year, 'month': previous_month.month},
|
||||
)
|
||||
|
||||
def get_next_month_url(self):
|
||||
next_month = self.get_next_month(self.date.date())
|
||||
return reverse(
|
||||
'chrono-manager-agenda-month-view',
|
||||
kwargs={'pk': self.agenda.id, 'year': next_month.year, 'month': next_month.month},
|
||||
)
|
||||
|
||||
def get_day(self):
|
||||
return '1'
|
||||
|
||||
def get_timetable_infos(self):
|
||||
timeperiods = itertools.chain(*(d.timeperiod_set.all() for d in self.agenda.prefetched_desks))
|
||||
timeperiods = sorted(timeperiods, key=lambda t: (t.weekday, t.start_time))
|
||||
|
@ -1419,18 +1480,21 @@ class AgendaMonthView(AgendaDateView, MonthArchiveView):
|
|||
hide_weekend = hide_weekend_timeperiod and hide_weekend_event
|
||||
|
||||
# avoid displaying empty first week
|
||||
first_week_offset = int(
|
||||
(hide_sunday and self.date.weekday() == 6) or (hide_weekend and self.date.weekday() == 5)
|
||||
)
|
||||
|
||||
first_week_offset = 0
|
||||
first_week_number = self.date.isocalendar()[1]
|
||||
if first_week_number >= 52:
|
||||
first_week_number = 0
|
||||
last_month_day = self.get_next_month(self.date.date()) - datetime.timedelta(days=1)
|
||||
last_week_number = last_month_day.isocalendar()[1]
|
||||
last_week_number = first_week_number
|
||||
if self.kind == 'month':
|
||||
first_week_offset = int(
|
||||
(hide_sunday and self.date.weekday() == 6) or (hide_weekend and self.date.weekday() == 5)
|
||||
)
|
||||
first_week_number = self.date.isocalendar()[1]
|
||||
if first_week_number >= 52:
|
||||
first_week_number = 0
|
||||
last_day = self.get_next(self.date.date()) - datetime.timedelta(days=1)
|
||||
last_week_number = last_day.isocalendar()[1]
|
||||
|
||||
if last_week_number < first_week_number: # new year
|
||||
last_week_number = 53
|
||||
if last_week_number < first_week_number: # new year
|
||||
last_week_number = 53
|
||||
|
||||
for week_number in range(first_week_number + first_week_offset, last_week_number + 1):
|
||||
yield self.get_week_timetable_infos(
|
||||
|
@ -1474,8 +1538,8 @@ class AgendaMonthView(AgendaDateView, MonthArchiveView):
|
|||
desks_len = len(desks)
|
||||
max_date = day.replace(hour=self.max_display.hour, minute=0)
|
||||
|
||||
# compute booking and opening hours only for current month
|
||||
if self.date.month != day.month:
|
||||
# compute booking and opening hours only for current month/week
|
||||
if self.kind == 'month' and timetable['other_month']:
|
||||
return timetable
|
||||
|
||||
while period <= max_date:
|
||||
|
@ -1536,6 +1600,73 @@ class AgendaMonthView(AgendaDateView, MonthArchiveView):
|
|||
return timetable
|
||||
|
||||
|
||||
class AgendaWeekView(AgendaWeekMonthMixin, AgendaDateView, WeekArchiveView):
|
||||
week_format = "%W"
|
||||
kind = 'week'
|
||||
|
||||
def get_template_names(self):
|
||||
if self.agenda.kind == 'virtual':
|
||||
return ['chrono/manager_meetings_agenda_week_view.html']
|
||||
return ['chrono/manager_%s_agenda_week_view.html' % self.agenda.kind]
|
||||
|
||||
def get_previous_week_url(self):
|
||||
previous_week = self.get_previous_week(self.date.date())
|
||||
return reverse(
|
||||
'chrono-manager-agenda-week-view',
|
||||
kwargs={'pk': self.agenda.id, 'year': previous_week.year, 'week': previous_week.strftime('%W')},
|
||||
)
|
||||
|
||||
def get_next_week_url(self):
|
||||
next_week = self.get_next_week(self.date.date())
|
||||
return reverse(
|
||||
'chrono-manager-agenda-week-view',
|
||||
kwargs={'pk': self.agenda.id, 'year': next_week.year, 'week': next_week.strftime('%W')},
|
||||
)
|
||||
|
||||
def get_next(self, date):
|
||||
return self.get_next_week(date)
|
||||
|
||||
def get_month(self):
|
||||
date = datetime.datetime.strptime('%s-W%s-1' % (self.get_year(), self.get_week()), "%Y-W%W-%w")
|
||||
return date.month
|
||||
|
||||
def get_day(self):
|
||||
date = datetime.datetime.strptime('%s-W%s-1' % (self.get_year(), self.get_week()), "%Y-W%W-%w")
|
||||
return date.day
|
||||
|
||||
|
||||
agenda_weekly_view = AgendaWeekView.as_view()
|
||||
|
||||
|
||||
class AgendaMonthView(AgendaWeekMonthMixin, AgendaDateView, MonthArchiveView):
|
||||
kind = 'month'
|
||||
|
||||
def get_template_names(self):
|
||||
if self.agenda.kind == 'virtual':
|
||||
return ['chrono/manager_meetings_agenda_month_view.html']
|
||||
return ['chrono/manager_%s_agenda_month_view.html' % self.agenda.kind]
|
||||
|
||||
def get_previous_month_url(self):
|
||||
previous_month = self.get_previous_month(self.date.date())
|
||||
return reverse(
|
||||
'chrono-manager-agenda-month-view',
|
||||
kwargs={'pk': self.agenda.id, 'year': previous_month.year, 'month': previous_month.month},
|
||||
)
|
||||
|
||||
def get_next_month_url(self):
|
||||
next_month = self.get_next_month(self.date.date())
|
||||
return reverse(
|
||||
'chrono-manager-agenda-month-view',
|
||||
kwargs={'pk': self.agenda.id, 'year': next_month.year, 'month': next_month.month},
|
||||
)
|
||||
|
||||
def get_next(self, date):
|
||||
return self.get_next_month(date)
|
||||
|
||||
def get_day(self):
|
||||
return '1'
|
||||
|
||||
|
||||
agenda_monthly_view = AgendaMonthView.as_view()
|
||||
|
||||
|
||||
|
|
|
@ -127,6 +127,12 @@ def test_events_agenda_redirect(app, admin_user):
|
|||
resp = app.get('/manage/agendas/%s/' % agenda_id, status=302)
|
||||
assert resp.location.endswith('/manage/agendas/%s/day/' % agenda.pk)
|
||||
|
||||
agenda.default_view = 'week'
|
||||
agenda.save()
|
||||
for agenda_id in [agenda.pk, agenda.slug]:
|
||||
resp = app.get('/manage/agendas/%s/' % agenda_id, status=302)
|
||||
assert resp.location.endswith('/manage/agendas/%s/week/' % agenda.pk)
|
||||
|
||||
|
||||
@freezegun.freeze_time('2020-07-12')
|
||||
def test_events_agenda_month_redirect(app, admin_user):
|
||||
|
@ -180,6 +186,58 @@ def test_events_agenda_month_redirect(app, admin_user):
|
|||
assert resp.location.endswith('/manage/agendas/%s/2020/7/' % agenda.pk)
|
||||
|
||||
|
||||
@freezegun.freeze_time('2020-07-12')
|
||||
def test_events_agenda_week_redirect(app, admin_user):
|
||||
agenda = Agenda.objects.create(label='Foo Bar', kind='events')
|
||||
|
||||
app = login(app)
|
||||
# no event, redirect to current week
|
||||
resp = app.get('/manage/agendas/%s/week/' % agenda.pk, status=302)
|
||||
assert resp.location.endswith('/manage/agendas/%s/2020/week/27/' % agenda.pk)
|
||||
|
||||
# only past events, redirect to last event month
|
||||
Event.objects.create(
|
||||
agenda=agenda,
|
||||
places=1,
|
||||
start_datetime=now() - datetime.timedelta(days=60),
|
||||
)
|
||||
resp = app.get('/manage/agendas/%s/week/' % agenda.pk, status=302)
|
||||
assert resp.location.endswith('/manage/agendas/%s/2020/week/19/' % agenda.pk)
|
||||
Event.objects.create(
|
||||
agenda=agenda,
|
||||
places=1,
|
||||
start_datetime=now() - datetime.timedelta(days=30),
|
||||
)
|
||||
resp = app.get('/manage/agendas/%s/week/' % agenda.pk, status=302)
|
||||
assert resp.location.endswith('/manage/agendas/%s/2020/week/23/' % agenda.pk)
|
||||
|
||||
# future events
|
||||
Event.objects.create(
|
||||
agenda=agenda,
|
||||
places=1,
|
||||
start_datetime=now() + datetime.timedelta(days=60),
|
||||
)
|
||||
resp = app.get('/manage/agendas/%s/week/' % agenda.pk, status=302)
|
||||
assert resp.location.endswith('/manage/agendas/%s/2020/week/36/' % agenda.pk)
|
||||
Event.objects.create(
|
||||
agenda=agenda,
|
||||
places=1,
|
||||
start_datetime=now() + datetime.timedelta(days=30),
|
||||
)
|
||||
resp = app.get('/manage/agendas/%s/week/' % agenda.pk, status=302)
|
||||
assert resp.location.endswith('/manage/agendas/%s/2020/week/32/' % agenda.pk)
|
||||
|
||||
# don't check events for meetings
|
||||
agenda.kind = 'virtual'
|
||||
agenda.save()
|
||||
resp = app.get('/manage/agendas/%s/week/' % agenda.pk, status=302)
|
||||
assert resp.location.endswith('/manage/agendas/%s/2020/week/27/' % agenda.pk)
|
||||
agenda.kind = 'meetings'
|
||||
agenda.save()
|
||||
resp = app.get('/manage/agendas/%s/week/' % agenda.pk, status=302)
|
||||
assert resp.location.endswith('/manage/agendas/%s/2020/week/27/' % agenda.pk)
|
||||
|
||||
|
||||
@freezegun.freeze_time('2020-07-12')
|
||||
def test_events_agenda_day_redirect(app, admin_user):
|
||||
agenda = Agenda.objects.create(label='Foo Bar', kind='events')
|
||||
|
@ -246,6 +304,12 @@ def test_meetings_agenda_redirect(app, admin_user):
|
|||
resp = app.get('/manage/agendas/%s/' % agenda_id, status=302)
|
||||
assert resp.location.endswith('/manage/agendas/%s/month/' % agenda.pk)
|
||||
|
||||
agenda.default_view = 'week'
|
||||
agenda.save()
|
||||
for agenda_id in [agenda.pk, agenda.slug]:
|
||||
resp = app.get('/manage/agendas/%s/' % agenda_id, status=302)
|
||||
assert resp.location.endswith('/manage/agendas/%s/week/' % agenda.pk)
|
||||
|
||||
|
||||
def test_virtual_agenda_redirect(app, admin_user):
|
||||
agenda = Agenda.objects.create(label='Foo Bar', kind='virtual')
|
||||
|
@ -261,6 +325,12 @@ def test_virtual_agenda_redirect(app, admin_user):
|
|||
resp = app.get('/manage/agendas/%s/' % agenda_id, status=302)
|
||||
assert resp.location.endswith('/manage/agendas/%s/month/' % agenda.pk)
|
||||
|
||||
agenda.default_view = 'week'
|
||||
agenda.save()
|
||||
for agenda_id in [agenda.pk, agenda.slug]:
|
||||
resp = app.get('/manage/agendas/%s/' % agenda_id, status=302)
|
||||
assert resp.location.endswith('/manage/agendas/%s/week/' % agenda.pk)
|
||||
|
||||
|
||||
def test_view_agendas_as_admin(app, admin_user):
|
||||
Agenda.objects.create(label='Bar Foo')
|
||||
|
@ -929,10 +999,11 @@ def test_agenda_day_view(app, admin_user, manager_user, api_user, get_proper_htm
|
|||
'view',
|
||||
(
|
||||
'/manage/agendas/%(agenda)s/%(year)d/%(month)d/%(day)d/',
|
||||
'/manage/agendas/%(agenda)s/%(year)d/week/%(week)d/',
|
||||
'/manage/agendas/%(agenda)s/%(year)d/%(month)d/',
|
||||
),
|
||||
)
|
||||
def test_agenda_day_month_view_backoffice_url_translation(
|
||||
def test_agenda_day_week_month_view_backoffice_url_translation(
|
||||
app, admin_user, manager_user, api_user, settings, view
|
||||
):
|
||||
agenda = Agenda.objects.create(label='New Example', kind='meetings')
|
||||
|
@ -959,7 +1030,13 @@ def test_agenda_day_month_view_backoffice_url_translation(
|
|||
booking = Booking.objects.get(pk=booking_id)
|
||||
assert booking.backoffice_url == backoffice_url
|
||||
date = booking.event.start_datetime
|
||||
url = view % {'agenda': agenda.id, 'year': date.year, 'month': date.month, 'day': date.day}
|
||||
url = view % {
|
||||
'agenda': agenda.id,
|
||||
'year': date.year,
|
||||
'month': date.month,
|
||||
'week': int(date.strftime('%W')),
|
||||
'day': date.day,
|
||||
}
|
||||
resp = app.get(url)
|
||||
assert resp.text.count('div class="booking') == 1
|
||||
assert backoffice_url in resp.text
|
||||
|
@ -1139,6 +1216,97 @@ def test_agenda_events_day_view_midnight(app, admin_user):
|
|||
assert len(resp.pyquery.find('.event-info')) == 1
|
||||
|
||||
|
||||
@freezegun.freeze_time('2020-10-01')
|
||||
def test_agenda_events_week_view(app, admin_user):
|
||||
agenda = Agenda.objects.create(label='Events', kind='events')
|
||||
Desk.objects.create(agenda=agenda, slug='_exceptions_holder')
|
||||
today = datetime.date.today()
|
||||
|
||||
login(app)
|
||||
resp = app.get('/manage/agendas/%s/%s/week/%s/' % (agenda.pk, today.year, today.strftime('%W')))
|
||||
assert 'Day view' in resp.text
|
||||
assert "This week doesn't have any event configured." in resp.text
|
||||
|
||||
# add event in a future month, a wednesday
|
||||
Event.objects.create(
|
||||
label='xyz', start_datetime=localtime().replace(day=11, month=11, year=2020), places=10, agenda=agenda
|
||||
)
|
||||
# current month still doesn't have events
|
||||
resp = app.get('/manage/agendas/%s/%s/week/%s/' % (agenda.id, today.year, today.strftime('%W')))
|
||||
assert "This week doesn't have any event configured." in resp.text
|
||||
|
||||
# add recurring event on every Wednesday
|
||||
start_datetime = localtime().replace(day=4, month=11, year=2020)
|
||||
event = Event.objects.create(
|
||||
label='abc',
|
||||
start_datetime=start_datetime,
|
||||
places=10,
|
||||
agenda=agenda,
|
||||
recurrence_days=[start_datetime.weekday()],
|
||||
recurrence_end_date=start_datetime + datetime.timedelta(days=60),
|
||||
)
|
||||
event.create_all_recurrences()
|
||||
|
||||
with CaptureQueriesContext(connection) as ctx:
|
||||
resp = app.get('/manage/agendas/%s/%s/week/%s/' % (agenda.id, 2020, 45))
|
||||
assert len(ctx.captured_queries) == 7
|
||||
assert len(resp.pyquery.find('.event-info')) == 2
|
||||
assert 'abc' in resp.pyquery.find('.event-info')[0].text
|
||||
assert 'xyz' in resp.pyquery.find('.event-info')[1].text
|
||||
|
||||
TimePeriodException.objects.create(
|
||||
desk=agenda.desk_set.get(),
|
||||
start_datetime=start_datetime + datetime.timedelta(days=6),
|
||||
end_datetime=start_datetime + datetime.timedelta(days=8),
|
||||
)
|
||||
agenda.update_event_recurrences()
|
||||
resp = app.get('/manage/agendas/%s/%s/week/%s/' % (agenda.id, 2020, 45))
|
||||
assert len(resp.pyquery.find('.event-info')) == 1
|
||||
assert 'Exception: 11/10/2020' in resp.pyquery.find('li')[4].text_content()
|
||||
assert 'xyz' in resp.pyquery.find('li')[5].text_content()
|
||||
|
||||
# create another event with recurrence, the same day/time
|
||||
start_datetime = localtime().replace(day=4, month=11, year=2020)
|
||||
event = Event.objects.create(
|
||||
label='def',
|
||||
start_datetime=start_datetime,
|
||||
places=10,
|
||||
agenda=agenda,
|
||||
recurrence_days=[start_datetime.weekday()],
|
||||
recurrence_end_date=start_datetime + datetime.timedelta(days=60),
|
||||
)
|
||||
event.create_all_recurrences()
|
||||
resp = app.get('/manage/agendas/%s/%s/week/%s/' % (agenda.id, 2020, 49))
|
||||
assert len(resp.pyquery.find('.event-info')) == 2
|
||||
|
||||
time = localtime(event.start_datetime).strftime('%H%M')
|
||||
resp = resp.click('Dec. 9, 2020, 1 a.m.', index=1)
|
||||
resp = resp.click('Options')
|
||||
resp.form['start_datetime_1'] = '13:12'
|
||||
resp = resp.form.submit(status=302).follow()
|
||||
agenda.update_event_recurrences()
|
||||
|
||||
resp = app.get('/manage/agendas/%s/%s/week/%s/' % (agenda.id, 2020, 49))
|
||||
assert len(resp.pyquery.find('.event-info')) == 2
|
||||
assert '1:12 p.m.' in resp.text
|
||||
|
||||
Event.objects.get(slug='abc--2020-12-02-%s' % time).cancel()
|
||||
resp = app.get('/manage/agendas/%s/%s/week/%s/' % (agenda.id, 2020, 48))
|
||||
assert 'Cancelled' in resp.text
|
||||
|
||||
|
||||
def test_agenda_events_week_view_midnight(app, admin_user):
|
||||
agenda = Agenda.objects.create(label='Events', kind='events', default_view='day')
|
||||
midnight = localtime(now().replace(day=1, month=11, year=2020)).replace(hour=0, minute=0)
|
||||
Event.objects.create(label='xyz', start_datetime=midnight, places=10, agenda=agenda)
|
||||
|
||||
login(app)
|
||||
resp = app.get('/manage/agendas/%s/week/' % agenda.pk)
|
||||
assert resp.location.endswith('/2020/week/43/')
|
||||
resp = resp.follow()
|
||||
assert len(resp.pyquery.find('.event-info')) == 1
|
||||
|
||||
|
||||
@freezegun.freeze_time('2020-10-01')
|
||||
def test_agenda_events_month_view(app, admin_user):
|
||||
agenda = Agenda.objects.create(label='Events', kind='events')
|
||||
|
@ -1365,7 +1533,8 @@ def test_agenda_month_view(app, admin_user, manager_user, api_user, get_proper_h
|
|||
resp = resp.click('Month view')
|
||||
assert resp.request.url.endswith('%s/%s/' % (today.year, today.month))
|
||||
|
||||
assert 'Day view' in resp.text # date view link should be present
|
||||
assert 'Day view' in resp.text # day view link should be present
|
||||
assert 'Week view' in resp.text # week view link should be present
|
||||
assert 'No opening hours this month.' in resp.text
|
||||
|
||||
today = datetime.date(2018, 11, 10) # fixed day
|
||||
|
@ -1744,6 +1913,383 @@ def test_agenda_month_view_event_outside_timeperiod(app, admin_user, kind):
|
|||
assert 'Saturday' in resp.text
|
||||
|
||||
|
||||
def test_agenda_week_view(app, admin_user, manager_user, api_user, get_proper_html_str):
|
||||
agenda = Agenda.objects.create(label='Passeports', kind='meetings')
|
||||
desk = Desk.objects.create(agenda=agenda, label='Desk A')
|
||||
today = datetime.date.today()
|
||||
|
||||
meetingtype = MeetingType(agenda=agenda, label='passeport', duration=20)
|
||||
meetingtype.save()
|
||||
|
||||
login(app)
|
||||
resp = app.get('/manage/agendas/%s/%d/%d/%d/' % (agenda.pk, today.year, today.month, today.day))
|
||||
assert 'Week view' in resp.text
|
||||
resp = resp.click('Week view')
|
||||
assert resp.request.url.endswith('%s/week/%s/' % (today.year, today.strftime('%W')))
|
||||
|
||||
assert 'Day view' in resp.text # day view link should be present
|
||||
assert 'Month view' in resp.text # month view link should be present
|
||||
assert 'No opening hours this week.' in resp.text
|
||||
|
||||
today = datetime.date(2018, 11, 10) # fixed day
|
||||
timeperiod_weekday = today.weekday()
|
||||
timeperiod = TimePeriod(
|
||||
desk=desk, weekday=timeperiod_weekday, start_time=datetime.time(10, 0), end_time=datetime.time(18, 0)
|
||||
)
|
||||
timeperiod.save()
|
||||
app.get('/manage/agendas/%s/%s/%s/' % (agenda.id, today.year, 72), status=404)
|
||||
resp = app.get('/manage/agendas/%s/%s/week/%s/' % (agenda.id, today.year, today.strftime('%W')))
|
||||
assert 'No opening hours this week.' not in resp.text
|
||||
assert '<div class="booking' not in resp.text
|
||||
assert resp.text.count('<tr') == 9
|
||||
|
||||
# check opening hours cells
|
||||
assert '<div class="opening-hours" style="height:800.0%;top:0.0%;width:97.0%;left:1.0%' in resp.text
|
||||
|
||||
# book some slots
|
||||
app.reset()
|
||||
app.authorization = ('Basic', ('john.doe', 'password'))
|
||||
resp = app.get('/api/agenda/%s/meetings/%s/datetimes/' % (agenda.slug, meetingtype.slug))
|
||||
booking_url = resp.json['data'][0]['api']['fillslot_url']
|
||||
booking_url2 = resp.json['data'][2]['api']['fillslot_url']
|
||||
booking = app.post(booking_url)
|
||||
booking_2 = app.post_json(
|
||||
booking_url2, params={'label': 'foo book', 'user_last_name': "bar's", 'url': 'http://baz/'}
|
||||
)
|
||||
|
||||
app.reset()
|
||||
login(app)
|
||||
date = Booking.objects.all()[0].event.start_datetime
|
||||
resp = app.get('/manage/agendas/%s/%d/week/%s/' % (agenda.id, date.year, date.strftime('%W')))
|
||||
assert resp.text.count('<div class="booking" style="left:1.0%;height:33.0%;') == 2 # booking cells
|
||||
assert resp.pyquery.find('div.booking a').not_('.cancel')[0].text.strip() == 'booked'
|
||||
assert resp.pyquery.find('div.booking a').not_('.cancel')[1].text.strip() == "foo book - bar's"
|
||||
assert get_proper_html_str('foo book - bar's') in resp
|
||||
assert len(resp.pyquery.find('span.desk')) == 0
|
||||
|
||||
agenda.booking_user_block_template = '<b>{{ booking.user_name }}</b> Foo Bar'
|
||||
agenda.save()
|
||||
resp = app.get('/manage/agendas/%s/%d/week/%s/' % (agenda.id, date.year, date.strftime('%W')))
|
||||
assert resp.pyquery.find('div.booking a').not_('.cancel')[0].text.strip() == '<b></b> Foo Bar'
|
||||
assert resp.pyquery.find('div.booking a').not_('.cancel')[1].text.strip() == "<b>bar's</b> Foo Bar"
|
||||
assert get_proper_html_str('<b>bar's</b> Foo Bar') in resp
|
||||
|
||||
desk = Desk.objects.create(agenda=agenda, label='Desk B')
|
||||
resp = app.get('/manage/agendas/%s/%d/week/%s/' % (agenda.id, date.year, date.strftime('%W')))
|
||||
assert len(resp.pyquery.find('span.desk')) == 2
|
||||
|
||||
timeperiod = TimePeriod(
|
||||
desk=desk, weekday=timeperiod_weekday, start_time=datetime.time(10, 0), end_time=datetime.time(18, 0)
|
||||
)
|
||||
timeperiod.save()
|
||||
|
||||
app.reset()
|
||||
booking_3 = app.post(booking_url)
|
||||
login(app)
|
||||
resp = app.get('/manage/agendas/%s/%d/week/%s/' % (agenda.id, today.year, today.strftime('%W')))
|
||||
|
||||
# count occurences of timeperiod weekday in current month
|
||||
assert resp.text.count('<div class="opening-hours"') == 2
|
||||
current_month = today.strftime('%Y-%m')
|
||||
if current_month in booking_url or current_month in booking_url2:
|
||||
assert resp.text.count('<div class="booking"') == 3
|
||||
|
||||
# cancel bookings
|
||||
app.reset()
|
||||
app.post(booking.json['api']['cancel_url'])
|
||||
app.post(booking_2.json['api']['cancel_url'])
|
||||
app.post(booking_3.json['api']['cancel_url'])
|
||||
|
||||
# make sure the are not
|
||||
login(app)
|
||||
resp = app.get('/manage/agendas/%s/%d/week/%s/' % (agenda.id, today.year, today.strftime('%W')))
|
||||
assert resp.text.count('<div class="booking"') == 0
|
||||
|
||||
# check December is correctly displayed
|
||||
today = datetime.date(2018, 12, 10)
|
||||
resp = app.get('/manage/agendas/%s/%d/week/%s/' % (agenda.id, today.year, today.strftime('%W')))
|
||||
assert 'No opening hours this week.' not in resp.text
|
||||
|
||||
# display exception
|
||||
unavailability_calendar = UnavailabilityCalendar.objects.create(label='calendar')
|
||||
TimePeriodException.objects.create(
|
||||
label='Calendar exception',
|
||||
unavailability_calendar=unavailability_calendar,
|
||||
start_datetime=make_aware(datetime.datetime(2018, 12, 15, 5, 0)),
|
||||
end_datetime=make_aware(datetime.datetime(2018, 12, 15, 14, 0)),
|
||||
)
|
||||
unavailability_calendar.desks.add(desk)
|
||||
TimePeriodException.objects.create(
|
||||
label='Exception for a December day',
|
||||
desk=desk,
|
||||
start_datetime=make_aware(datetime.datetime(2018, 12, 15, 14, 0)),
|
||||
end_datetime=make_aware(datetime.datetime(2018, 12, 15, 23, 0)),
|
||||
)
|
||||
TimePeriodException.objects.create(
|
||||
label='Exception spanning multiple days',
|
||||
desk=desk,
|
||||
start_datetime=make_aware(datetime.datetime(2018, 12, 11, 14, 0)),
|
||||
end_datetime=make_aware(datetime.datetime(2018, 12, 13, 16, 0)),
|
||||
)
|
||||
with CaptureQueriesContext(connection) as ctx:
|
||||
resp = app.get('/manage/agendas/%s/%d/week/%s/' % (agenda.id, today.year, today.strftime('%W')))
|
||||
assert len(ctx.captured_queries) == 10
|
||||
assert resp.pyquery.find('.exception-hours')[0].attrib == {
|
||||
'class': 'exception-hours',
|
||||
'style': 'height:400.0%;top:400.0%;width:48.0%;left:50.0%;',
|
||||
'title': 'Exception spanning multiple days',
|
||||
}
|
||||
assert resp.pyquery.find('.exception-hours')[1].attrib == {
|
||||
'class': 'exception-hours',
|
||||
'style': 'height:800.0%;top:0.0%;width:48.0%;left:50.0%;',
|
||||
'title': 'Exception spanning multiple days',
|
||||
}
|
||||
assert resp.pyquery.find('.exception-hours')[2].attrib == {
|
||||
'class': 'exception-hours',
|
||||
'style': 'height:600.0%;top:0.0%;width:48.0%;left:50.0%;',
|
||||
'title': 'Exception spanning multiple days',
|
||||
}
|
||||
assert resp.pyquery.find('.exception-hours')[3].attrib == {
|
||||
'class': 'exception-hours',
|
||||
'style': 'height:400.0%;top:0.0%;width:48.0%;left:50.0%;',
|
||||
'title': 'Calendar exception',
|
||||
}
|
||||
assert resp.pyquery.find('.exception-hours')[4].attrib == {
|
||||
'class': 'exception-hours',
|
||||
'style': 'height:400.0%;top:400.0%;width:48.0%;left:50.0%;',
|
||||
'title': 'Exception for a December day',
|
||||
}
|
||||
|
||||
|
||||
@pytest.mark.parametrize('kind', ['meetings', 'virtual'])
|
||||
def test_agenda_week_view_weekend(app, admin_user, kind):
|
||||
week, year = '02', 2019
|
||||
monday = 0
|
||||
if kind == 'meetings':
|
||||
agenda = Agenda.objects.create(label='Passeports', kind='meetings')
|
||||
desk = Desk.objects.create(agenda=agenda, label='Desk A')
|
||||
else:
|
||||
agenda = Agenda.objects.create(label='Virtual', kind='virtual')
|
||||
real_agenda = Agenda.objects.create(label='Real 1', kind='meetings')
|
||||
VirtualMember.objects.create(virtual_agenda=agenda, real_agenda=real_agenda)
|
||||
desk = Desk.objects.create(agenda=real_agenda, label='New Desk')
|
||||
TimePeriod.objects.create(
|
||||
desk=desk, weekday=monday, start_time=datetime.time(10, 0), end_time=datetime.time(18, 0)
|
||||
)
|
||||
|
||||
login(app)
|
||||
resp = app.get('/manage/agendas/%s/%s/week/%s/' % (agenda.id, year, week))
|
||||
assert 'Sunday' not in resp.text
|
||||
assert 'Saturday' not in resp.text
|
||||
# Month starts a Tuesday, but monday is displayed
|
||||
assert len(resp.pyquery.find('tbody tr:first th.weekday:empty')) == 0
|
||||
|
||||
week, year = 21, 2019 # month starts a Saturday
|
||||
resp = app.get('/manage/agendas/%s/%s/week/%s/' % (agenda.id, year, week))
|
||||
assert len(resp.pyquery.find('tbody tr:first th.weekday:empty')) == 0
|
||||
|
||||
saturday = 5
|
||||
timeperiod_sat = TimePeriod.objects.create(
|
||||
desk=desk, weekday=saturday, start_time=datetime.time(10, 0), end_time=datetime.time(18, 0)
|
||||
)
|
||||
resp = app.get('/manage/agendas/%s/%s/week/%s/' % (agenda.id, year, week))
|
||||
assert 'Sunday' not in resp.text
|
||||
assert 'Saturday' in resp.text
|
||||
assert len(resp.pyquery.find('tbody tr:first th.weekday:empty')) == 0
|
||||
|
||||
sunday = 6
|
||||
TimePeriod.objects.create(
|
||||
desk=desk, weekday=sunday, start_time=datetime.time(10, 0), end_time=datetime.time(18, 0)
|
||||
)
|
||||
resp = app.get('/manage/agendas/%s/%s/week/%s/' % (agenda.id, year, week))
|
||||
assert 'Sunday' in resp.text
|
||||
assert 'Saturday' in resp.text
|
||||
|
||||
timeperiod_sat.delete()
|
||||
resp = app.get('/manage/agendas/%s/%s/week/%s/' % (agenda.id, year, week))
|
||||
assert 'Sunday' in resp.text
|
||||
assert 'Saturday' in resp.text
|
||||
|
||||
|
||||
@pytest.mark.parametrize('kind', ['meetings', 'virtual'])
|
||||
def test_agenda_week_view_dst_change(app, admin_user, kind):
|
||||
if kind == 'meetings':
|
||||
agenda = Agenda.objects.create(label='Passeports', kind='meetings')
|
||||
desk = Desk.objects.create(agenda=agenda, label='Desk A')
|
||||
meetingtype = MeetingType.objects.create(agenda=agenda, label='passeport', duration=20)
|
||||
else:
|
||||
agenda = Agenda.objects.create(label='Virtual', kind='virtual')
|
||||
real_agenda = Agenda.objects.create(label='Real 1', kind='meetings')
|
||||
VirtualMember.objects.create(virtual_agenda=agenda, real_agenda=real_agenda)
|
||||
desk = Desk.objects.create(agenda=real_agenda, label='New Desk')
|
||||
meetingtype = MeetingType.objects.create(agenda=real_agenda, label='passeport', duration=20)
|
||||
|
||||
for weekday in range(0, 7): # open all mornings
|
||||
TimePeriod.objects.create(
|
||||
desk=desk, weekday=weekday, start_time=datetime.time(9, 0), end_time=datetime.time(12, 0)
|
||||
)
|
||||
|
||||
login(app)
|
||||
for date in ('2019-10-28', '2019-11-03'):
|
||||
# dst change was on 2019-11-03
|
||||
with freezegun.freeze_time(date):
|
||||
resp = app.get('/manage/agendas/%s/2019/week/43/' % agenda.id)
|
||||
# check all days are correctly aligned
|
||||
assert resp.text.count('height:300.0%;top:0.0%') == 7
|
||||
|
||||
# book some slots
|
||||
for date_tuple in [(2019, 10, 29, 10, 0), (2019, 10, 30, 10, 0)]:
|
||||
event = Event.objects.create(
|
||||
agenda=desk.agenda,
|
||||
places=1,
|
||||
desk=desk,
|
||||
meeting_type=meetingtype,
|
||||
start_datetime=localtime(make_aware(datetime.datetime(*date_tuple))),
|
||||
)
|
||||
Booking.objects.create(event=event)
|
||||
|
||||
# check booked slots are similarly aligned
|
||||
resp = app.get('/manage/agendas/%s/2019/week/43/' % agenda.id)
|
||||
assert resp.text.count('height:33.0%;top:100.0%;') == 2
|
||||
|
||||
|
||||
@pytest.mark.parametrize('kind', ['meetings', 'virtual'])
|
||||
def test_agenda_week_view_januaries(app, admin_user, kind):
|
||||
if kind == 'meetings':
|
||||
agenda = Agenda.objects.create(label='Passports', kind='meetings')
|
||||
desk = Desk.objects.create(agenda=agenda, label='Desk A')
|
||||
MeetingType.objects.create(agenda=agenda, label='passport', duration=20)
|
||||
else:
|
||||
agenda = Agenda.objects.create(label='Virtual', kind='virtual')
|
||||
real_agenda = Agenda.objects.create(label='Real 1', kind='meetings')
|
||||
VirtualMember.objects.create(virtual_agenda=agenda, real_agenda=real_agenda)
|
||||
desk = Desk.objects.create(agenda=real_agenda, label='New Desk')
|
||||
MeetingType.objects.create(agenda=real_agenda, label='passport', duration=20)
|
||||
TimePeriod(desk=desk, weekday=2, start_time=datetime.time(9, 0), end_time=datetime.time(12, 0)).save()
|
||||
|
||||
for year in range(2020, 2030):
|
||||
date = datetime.date(year, 1, 1)
|
||||
with freezegun.freeze_time(date):
|
||||
login(app)
|
||||
resp = app.get('/manage/agendas/%s/%s/week/01/' % (agenda.id, date.year))
|
||||
assert resp.text.count('<th></th>') == 1
|
||||
|
||||
|
||||
@pytest.mark.parametrize('kind', ['meetings', 'virtual'])
|
||||
def test_agenda_week_view_event_outside_timeperiod(app, admin_user, kind):
|
||||
middle_day = now().replace(day=15)
|
||||
middle_day = middle_day + datetime.timedelta(days=4 - middle_day.weekday())
|
||||
if kind == 'meetings':
|
||||
agenda = Agenda.objects.create(label='New Example', kind='meetings')
|
||||
desk = Desk.objects.create(agenda=agenda, label='New Desk')
|
||||
meetingtype = MeetingType.objects.create(agenda=agenda, label='Bar', duration=30)
|
||||
else:
|
||||
agenda = Agenda.objects.create(label='Virtual', kind='virtual')
|
||||
real_agenda = Agenda.objects.create(label='Real 1', kind='meetings')
|
||||
VirtualMember.objects.create(virtual_agenda=agenda, real_agenda=real_agenda)
|
||||
desk = Desk.objects.create(agenda=real_agenda, label='New Desk')
|
||||
meetingtype = MeetingType.objects.create(agenda=real_agenda, label='passport', duration=20)
|
||||
login(app)
|
||||
|
||||
# no time period - no events
|
||||
resp = app.get('/manage/agendas/%s/%d/week/%s/' % (agenda.pk, middle_day.year, middle_day.strftime('%W')))
|
||||
assert 'No opening hours this week.' in resp.text
|
||||
assert 'div class="booking' not in resp.text
|
||||
|
||||
# book some slots
|
||||
middle_day = now().replace(day=15)
|
||||
for hour, minute in [(9, 0), (17, 0)]:
|
||||
event = Event.objects.create(
|
||||
agenda=desk.agenda,
|
||||
places=1,
|
||||
desk=desk,
|
||||
meeting_type=meetingtype,
|
||||
start_datetime=localtime(now().replace(day=middle_day.day - middle_day.weekday() + 2)).replace(
|
||||
hour=hour, minute=minute
|
||||
),
|
||||
)
|
||||
Booking.objects.create(event=event)
|
||||
|
||||
# no time period - events are displayed
|
||||
resp = app.get('/manage/agendas/%s/%d/week/%s/' % (agenda.pk, middle_day.year, middle_day.strftime('%W')))
|
||||
assert resp.text.count('div class="booking') == 2
|
||||
|
||||
# bookings are cancelled
|
||||
Booking.objects.update(cancellation_datetime=now())
|
||||
resp = app.get('/manage/agendas/%s/%d/week/%s/' % (agenda.pk, middle_day.year, middle_day.strftime('%W')))
|
||||
assert 'No opening hours this week.' in resp.text
|
||||
assert resp.text.count('div class="booking') == 0
|
||||
|
||||
# events outside time period
|
||||
Booking.objects.update(cancellation_datetime=None) # reset
|
||||
TimePeriod.objects.create(
|
||||
desk=desk, weekday=2, start_time=datetime.time(10, 0), end_time=datetime.time(16, 0)
|
||||
)
|
||||
resp = app.get('/manage/agendas/%s/%d/week/%s/' % (agenda.pk, middle_day.year, middle_day.strftime('%W')))
|
||||
assert resp.text.count('div class="booking') == 2
|
||||
assert '<div class="opening-hours" style="height:600.0%;top:100.0%;width:97.0%;left:1.0%' in resp.text
|
||||
assert 'Sunday' not in resp.text
|
||||
assert 'Saturday' not in resp.text
|
||||
|
||||
# create an event on saturday
|
||||
middle_day = now().replace(day=15)
|
||||
middle_day = middle_day + datetime.timedelta(days=5 - middle_day.weekday())
|
||||
event = Event.objects.create(
|
||||
agenda=desk.agenda,
|
||||
places=1,
|
||||
desk=desk,
|
||||
meeting_type=meetingtype,
|
||||
start_datetime=localtime(now()).replace(day=middle_day.day, hour=10, minute=0),
|
||||
)
|
||||
Booking.objects.create(event=event)
|
||||
resp = app.get('/manage/agendas/%s/%d/week/%s/' % (agenda.pk, middle_day.year, middle_day.strftime('%W')))
|
||||
assert resp.text.count('div class="booking') == 3
|
||||
assert 'Sunday' not in resp.text
|
||||
assert 'Saturday' in resp.text
|
||||
# bookings are cancelled
|
||||
Booking.objects.update(cancellation_datetime=now())
|
||||
resp = app.get('/manage/agendas/%s/%d/week/%s/' % (agenda.pk, middle_day.year, middle_day.strftime('%W')))
|
||||
assert resp.text.count('div class="booking') == 0
|
||||
# and a timeperiod
|
||||
Booking.objects.update(cancellation_datetime=None) # reset
|
||||
TimePeriod.objects.create(
|
||||
desk=desk, weekday=5, start_time=datetime.time(11, 0), end_time=datetime.time(12, 0)
|
||||
)
|
||||
resp = app.get('/manage/agendas/%s/%d/week/%s/' % (agenda.pk, middle_day.year, middle_day.strftime('%W')))
|
||||
assert resp.text.count('div class="booking') == 3
|
||||
assert 'Sunday' not in resp.text
|
||||
assert 'Saturday' in resp.text
|
||||
|
||||
# create an event on sunday
|
||||
middle_day = now().replace(day=15)
|
||||
middle_day = middle_day + datetime.timedelta(days=6 - middle_day.weekday())
|
||||
event = Event.objects.create(
|
||||
agenda=desk.agenda,
|
||||
places=1,
|
||||
desk=desk,
|
||||
meeting_type=meetingtype,
|
||||
start_datetime=localtime(now()).replace(day=middle_day.day, hour=10, minute=0),
|
||||
)
|
||||
Booking.objects.create(event=event)
|
||||
resp = app.get('/manage/agendas/%s/%d/week/%s/' % (agenda.pk, middle_day.year, middle_day.strftime('%W')))
|
||||
assert resp.text.count('div class="booking') == 4
|
||||
assert 'Sunday' in resp.text
|
||||
assert 'Saturday' in resp.text
|
||||
# bookings are cancelled
|
||||
Booking.objects.update(cancellation_datetime=now())
|
||||
resp = app.get('/manage/agendas/%s/%d/week/%s/' % (agenda.pk, middle_day.year, middle_day.strftime('%W')))
|
||||
assert resp.text.count('div class="booking') == 0
|
||||
# and a timeperiod
|
||||
Booking.objects.update(cancellation_datetime=None) # reset
|
||||
TimePeriod.objects.create(
|
||||
desk=desk, weekday=6, start_time=datetime.time(11, 0), end_time=datetime.time(12, 0)
|
||||
)
|
||||
resp = app.get('/manage/agendas/%s/%d/week/%s/' % (agenda.pk, middle_day.year, middle_day.strftime('%W')))
|
||||
assert resp.text.count('div class="booking') == 4
|
||||
assert 'Sunday' in resp.text
|
||||
assert 'Saturday' in resp.text
|
||||
|
||||
|
||||
def test_agenda_view_event(app, manager_user):
|
||||
agenda = Agenda(label='Foo bar')
|
||||
agenda.view_role = manager_user.groups.all()[0]
|
||||
|
@ -1997,6 +2543,129 @@ def test_virtual_agenda_day_view(app, admin_user, manager_user, get_proper_html_
|
|||
assert 'exceptions-hours' not in resp.text
|
||||
|
||||
|
||||
def test_virtual_agenda_week_view(app, admin_user, get_proper_html_str):
|
||||
agenda = Agenda.objects.create(label='Virtual', kind='virtual')
|
||||
real_agenda_1 = Agenda.objects.create(label='Real 1', kind='meetings')
|
||||
real_agenda_2 = Agenda.objects.create(label='Real 2', kind='meetings')
|
||||
VirtualMember.objects.create(virtual_agenda=agenda, real_agenda=real_agenda_1)
|
||||
VirtualMember.objects.create(virtual_agenda=agenda, real_agenda=real_agenda_2)
|
||||
|
||||
desk1 = Desk.objects.create(agenda=real_agenda_1, label='New Desk')
|
||||
desk2 = Desk.objects.create(agenda=real_agenda_2, label='New Desk')
|
||||
today = datetime.date.today()
|
||||
|
||||
meetingtype1 = MeetingType.objects.create(agenda=real_agenda_1, label='Bar', duration=30)
|
||||
meetingtype2 = MeetingType.objects.create(agenda=real_agenda_2, label='Bar', duration=30)
|
||||
|
||||
login(app)
|
||||
resp = app.get('/manage/agendas/%s/%d/%d/%d/' % (agenda.pk, today.year, today.month, today.day))
|
||||
assert 'Week view' in resp.text
|
||||
resp = resp.click('Week view')
|
||||
assert resp.request.url.endswith('%s/week/%s/' % (today.year, today.strftime('%W')))
|
||||
|
||||
assert 'Day view' in resp.text # day view link should be present
|
||||
assert 'Month view' in resp.text # month view link should be present
|
||||
assert 'No opening hours this week.' in resp.text
|
||||
|
||||
today = datetime.date(2018, 11, 10) # fixed day
|
||||
timeperiod_weekday = today.weekday()
|
||||
TimePeriod.objects.create(
|
||||
desk=desk1, weekday=timeperiod_weekday, start_time=datetime.time(10, 0), end_time=datetime.time(18, 0)
|
||||
)
|
||||
resp = app.get('/manage/agendas/%s/%s/week/%s/' % (agenda.id, today.year, today.strftime('%W')))
|
||||
assert 'No opening hours this week.' not in resp.text
|
||||
assert '<div class="booking' not in resp.text
|
||||
assert resp.text.count('<tr') == 9
|
||||
|
||||
# check opening hours cells
|
||||
assert '<div class="opening-hours" style="height:800.0%;top:0.0%;width:48.0%;left:1.0%' in resp.text
|
||||
|
||||
# book some slots
|
||||
for hour, minute in [(10, 30), (14, 0)]:
|
||||
event = Event.objects.create(
|
||||
agenda=real_agenda_1,
|
||||
places=1,
|
||||
desk=desk1,
|
||||
meeting_type=meetingtype1,
|
||||
start_datetime=now().replace(hour=hour, minute=minute),
|
||||
)
|
||||
Booking.objects.create(event=event)
|
||||
event = Event.objects.create(
|
||||
agenda=real_agenda_2,
|
||||
places=1,
|
||||
desk=desk2,
|
||||
meeting_type=meetingtype2,
|
||||
start_datetime=now().replace(hour=hour, minute=minute),
|
||||
)
|
||||
Booking.objects.create(event=event, label='foo', user_last_name="bar's")
|
||||
|
||||
date = Booking.objects.all()[0].event.start_datetime
|
||||
resp = app.get('/manage/agendas/%s/%d/week/%s/' % (agenda.id, date.year, date.strftime('%W')))
|
||||
assert resp.text.count('<div class="booking" style="left:1.0%;height:50.0%;') == 2 # booking cells
|
||||
assert (
|
||||
resp.text.count('<div class="booking" style="left:50.0%;height:50.0%;min-height:50.0%;') == 2
|
||||
) # booking cells
|
||||
assert resp.pyquery.find('div.booking a').not_('.cancel')[0].text.strip() == 'booked'
|
||||
assert resp.pyquery.find('div.booking a').not_('.cancel')[1].text.strip() == "foo - bar's"
|
||||
assert resp.pyquery.find('div.booking a').not_('.cancel')[2].text.strip() == 'booked'
|
||||
assert resp.pyquery.find('div.booking a').not_('.cancel')[3].text.strip() == "foo - bar's"
|
||||
assert get_proper_html_str('foo - bar's') in resp
|
||||
|
||||
real_agenda_1.booking_user_block_template = '<b>{{ booking.user_name }}</b> Foo Bar'
|
||||
real_agenda_1.save()
|
||||
real_agenda_2.booking_user_block_template = '<b>{{ booking.user_name }}</b> Bar Foo'
|
||||
real_agenda_2.save()
|
||||
resp = app.get('/manage/agendas/%s/%d/%d/' % (agenda.id, date.year, date.month))
|
||||
assert resp.pyquery.find('div.booking a').not_('.cancel')[0].text.strip() == '<b></b> Foo Bar'
|
||||
assert resp.pyquery.find('div.booking a').not_('.cancel')[1].text.strip() == "<b>bar's</b> Bar Foo"
|
||||
assert resp.pyquery.find('div.booking a').not_('.cancel')[2].text.strip() == '<b></b> Foo Bar'
|
||||
assert resp.pyquery.find('div.booking a').not_('.cancel')[3].text.strip() == "<b>bar's</b> Bar Foo"
|
||||
assert get_proper_html_str('<b>bar's</b> Bar Foo') in resp
|
||||
|
||||
# cancel a booking
|
||||
booking = Booking.objects.first()
|
||||
booking.cancel()
|
||||
resp = app.get('/manage/agendas/%s/%d/week/%s/' % (agenda.id, date.year, date.strftime('%W')))
|
||||
assert resp.text.count('<div class="booking"') == 3
|
||||
|
||||
# check December is correctly displayed
|
||||
today = datetime.date(2018, 12, 10)
|
||||
resp = app.get('/manage/agendas/%s/%d/week/%s/' % (agenda.id, today.year, today.strftime('%W')))
|
||||
assert 'No opening hours this month.' not in resp.text
|
||||
|
||||
# display exception
|
||||
TimePeriodException.objects.create(
|
||||
label='Exception for a December day',
|
||||
desk=desk1,
|
||||
start_datetime=make_aware(datetime.datetime(2018, 12, 15, 5, 0)),
|
||||
end_datetime=make_aware(datetime.datetime(2018, 12, 15, 23, 0)),
|
||||
)
|
||||
with CaptureQueriesContext(connection) as ctx:
|
||||
resp = app.get('/manage/agendas/%s/%d/week/%s/' % (agenda.id, today.year, today.strftime('%W')))
|
||||
assert len(ctx.captured_queries) == 12
|
||||
assert len(resp.pyquery.find('.exception-hours')) == 1
|
||||
assert resp.pyquery.find('.exception-hours')[0].attrib == {
|
||||
'class': 'exception-hours',
|
||||
'style': 'height:800.0%;top:0.0%;width:48.0%;left:1.0%;',
|
||||
'title': 'Exception for a December day',
|
||||
}
|
||||
|
||||
# display excluded period
|
||||
TimePeriod.objects.create(
|
||||
agenda=agenda, weekday=today.weekday(), start_time=datetime.time(13, 0), end_time=datetime.time(23, 0)
|
||||
)
|
||||
resp = app.get('/manage/agendas/%s/%d/week/%s/' % (agenda.id, today.year, today.strftime('%W')))
|
||||
assert len(resp.pyquery.find('.exception-hours')) == 3
|
||||
assert resp.pyquery.find('.exception-hours')[0].attrib == {
|
||||
'class': 'exception-hours',
|
||||
'style': 'height:500.0%;top:300.0%;width:48.0%;left:1.0%;',
|
||||
}
|
||||
assert resp.pyquery.find('.exception-hours')[1].attrib == {
|
||||
'class': 'exception-hours',
|
||||
'style': 'height:500.0%;top:300.0%;width:48.0%;left:50.0%;',
|
||||
}
|
||||
|
||||
|
||||
def test_virtual_agenda_month_view(app, admin_user, get_proper_html_str):
|
||||
agenda = Agenda.objects.create(label='Virtual', kind='virtual')
|
||||
real_agenda_1 = Agenda.objects.create(label='Real 1', kind='meetings')
|
||||
|
@ -2017,7 +2686,8 @@ def test_virtual_agenda_month_view(app, admin_user, get_proper_html_str):
|
|||
resp = resp.click('Month view')
|
||||
assert resp.request.url.endswith('%s/%s/' % (today.year, today.month))
|
||||
|
||||
assert 'Day view' in resp.text # date view link should be present
|
||||
assert 'Day view' in resp.text # day view link should be present
|
||||
assert 'Week view' in resp.text # week view link should be present
|
||||
assert 'No opening hours this month.' in resp.text
|
||||
|
||||
today = datetime.date(2018, 11, 10) # fixed day
|
||||
|
|
|
@ -220,6 +220,296 @@ def test_day_view_resource_as_manager(app, manager_user):
|
|||
app.get('/manage/resource/%s/%d/%d/%d/' % (resource.pk, today.year, today.month, today.day), status=403)
|
||||
|
||||
|
||||
@freezegun.freeze_time('2020-06-15')
|
||||
def test_resource_week_view(app, admin_user, get_proper_html_str):
|
||||
resource = Resource.objects.create(label='Foo bar')
|
||||
agenda = Agenda.objects.create(label='Agenda', kind='meetings')
|
||||
agenda.resources.add(resource)
|
||||
desk = Desk.objects.create(agenda=agenda, label='Desk')
|
||||
meetingtype = MeetingType.objects.create(agenda=agenda, label='Bar', duration=20)
|
||||
TimePeriod.objects.create(
|
||||
desk=desk, weekday=0, start_time=datetime.time(10, 0), end_time=datetime.time(18, 0)
|
||||
)
|
||||
|
||||
login(app)
|
||||
today = datetime.date(2018, 11, 10) # fixed day
|
||||
app.get('/manage/resource/%s/%s/%s/' % (resource.pk, today.year, 72), status=404)
|
||||
resp = app.get('/manage/resource/%s/%s/week/%s/' % (resource.pk, today.year, today.strftime('%W')))
|
||||
assert '<div class="booking' not in resp.text
|
||||
assert resp.text.count('<tr') == 9
|
||||
|
||||
# book some slots
|
||||
for hour, minute in [(10, 30), (14, 0)]:
|
||||
event = Event.objects.create(
|
||||
agenda=agenda,
|
||||
places=1,
|
||||
desk=desk,
|
||||
meeting_type=meetingtype,
|
||||
start_datetime=now().replace(hour=hour, minute=minute),
|
||||
)
|
||||
event.resources.add(resource)
|
||||
if hour == 10:
|
||||
Booking.objects.create(event=event)
|
||||
else:
|
||||
Booking.objects.create(event=event, label='foo', user_last_name="bar's")
|
||||
|
||||
today = datetime.date.today()
|
||||
with CaptureQueriesContext(connection) as ctx:
|
||||
resp = app.get('/manage/resource/%s/%s/week/%s/' % (resource.pk, today.year, today.strftime('%W')))
|
||||
assert len(ctx.captured_queries) == 8
|
||||
assert resp.text.count('<div class="booking" style="height:33.0%;') == 2 # booking cells
|
||||
assert resp.pyquery.find('div.booking a').not_('.cancel')[0].text.strip() == 'booked'
|
||||
assert resp.pyquery.find('div.booking a').not_('.cancel')[1].text.strip() == "foo - bar's"
|
||||
assert get_proper_html_str('foo - bar's') in resp
|
||||
|
||||
agenda.booking_user_block_template = '<b>{{ booking.user_name }}</b> Foo Bar'
|
||||
agenda.save()
|
||||
resp = app.get('/manage/resource/%s/%s/week/%s/' % (resource.pk, today.year, today.strftime('%W')))
|
||||
assert resp.pyquery.find('div.booking a').not_('.cancel')[0].text.strip() == '<b></b> Foo Bar'
|
||||
assert resp.pyquery.find('div.booking a').not_('.cancel')[1].text.strip() == "<b>bar's</b> Foo Bar"
|
||||
assert get_proper_html_str('<b>bar's</b> Foo Bar') in resp
|
||||
|
||||
# cancel booking
|
||||
booking = Booking.objects.first()
|
||||
booking.cancel()
|
||||
|
||||
# make sure the are not
|
||||
resp = app.get('/manage/resource/%s/%s/week/%s/' % (resource.pk, today.year, today.strftime('%W')))
|
||||
assert resp.text.count('<div class="booking"') == 1
|
||||
|
||||
|
||||
def test_resource_week_view_weekend(app, admin_user):
|
||||
resource = Resource.objects.create(label='Foo bar')
|
||||
agenda = Agenda.objects.create(label='Agenda', kind='meetings')
|
||||
agenda.resources.add(resource)
|
||||
desk = Desk.objects.create(agenda=agenda, label='Desk')
|
||||
MeetingType.objects.create(agenda=agenda, label='Bar', duration=30)
|
||||
monday = 0
|
||||
TimePeriod.objects.create(
|
||||
desk=desk, weekday=monday, start_time=datetime.time(10, 0), end_time=datetime.time(18, 0)
|
||||
)
|
||||
week, year = '01', 2019
|
||||
|
||||
login(app)
|
||||
resp = app.get('/manage/resource/%s/%s/week/%s/' % (resource.pk, year, week))
|
||||
assert 'Sunday' not in resp.text
|
||||
assert 'Saturday' not in resp.text
|
||||
# Month starts a Tuesday, but monday is displayed
|
||||
assert len(resp.pyquery.find('tbody tr:first th.weekday:empty')) == 0
|
||||
|
||||
week, year = 21, 2019 # month starts a Saturday
|
||||
resp = app.get('/manage/resource/%s/%s/week/%s/' % (resource.pk, year, week))
|
||||
assert len(resp.pyquery.find('tbody tr:first th.weekday:empty')) == 0
|
||||
|
||||
saturday = 5
|
||||
timeperiod_sat = TimePeriod.objects.create(
|
||||
desk=desk, weekday=saturday, start_time=datetime.time(10, 0), end_time=datetime.time(18, 0)
|
||||
)
|
||||
resp = app.get('/manage/resource/%s/%s/week/%s/' % (resource.pk, year, week))
|
||||
assert 'Sunday' not in resp.text
|
||||
assert 'Saturday' in resp.text
|
||||
assert len(resp.pyquery.find('tbody tr:first th.weekday:empty')) == 0
|
||||
|
||||
sunday = 6
|
||||
TimePeriod.objects.create(
|
||||
desk=desk, weekday=sunday, start_time=datetime.time(10, 0), end_time=datetime.time(18, 0)
|
||||
)
|
||||
resp = app.get('/manage/resource/%s/%s/week/%s/' % (resource.pk, year, week))
|
||||
assert 'Sunday' in resp.text
|
||||
assert 'Saturday' in resp.text
|
||||
|
||||
timeperiod_sat.delete()
|
||||
resp = app.get('/manage/resource/%s/%s/week/%s/' % (resource.pk, year, week))
|
||||
assert 'Sunday' in resp.text
|
||||
assert 'Saturday' in resp.text
|
||||
|
||||
|
||||
def test_resource_week_view_dst_change(app, admin_user):
|
||||
resource = Resource.objects.create(label='Foo bar')
|
||||
agenda = Agenda.objects.create(label='Agenda', kind='meetings')
|
||||
agenda.resources.add(resource)
|
||||
desk = Desk.objects.create(agenda=agenda, label='Desk')
|
||||
meetingtype = MeetingType.objects.create(agenda=agenda, label='Bar', duration=30)
|
||||
TimePeriod.objects.create(
|
||||
desk=desk, weekday=0, start_time=datetime.time(9, 0), end_time=datetime.time(12, 0)
|
||||
)
|
||||
|
||||
login(app)
|
||||
# book some slots
|
||||
with freezegun.freeze_time('2019-10-01'):
|
||||
for start_datetime in [
|
||||
make_aware(datetime.datetime(2019, 10, 2, 10, 0)),
|
||||
make_aware(datetime.datetime(2019, 10, 29, 10, 0)),
|
||||
]:
|
||||
event = Event.objects.create(
|
||||
agenda=agenda,
|
||||
places=1,
|
||||
desk=desk,
|
||||
meeting_type=meetingtype,
|
||||
start_datetime=start_datetime,
|
||||
)
|
||||
event.resources.add(resource)
|
||||
Booking.objects.create(event=event)
|
||||
|
||||
# check booked slots are similarly aligned
|
||||
resp = app.get('/manage/resource/%s/2019/week/43/' % resource.pk)
|
||||
assert resp.text.count('height:50.0%;top:100.0%') == 1
|
||||
|
||||
|
||||
def test_resource_week_view_januaries(app, admin_user):
|
||||
resource = Resource.objects.create(label='Foo bar')
|
||||
agenda = Agenda.objects.create(label='Agenda', kind='meetings')
|
||||
agenda.resources.add(resource)
|
||||
desk = Desk.objects.create(agenda=agenda, label='Desk')
|
||||
TimePeriod(desk=desk, weekday=2, start_time=datetime.time(9, 0), end_time=datetime.time(12, 0)).save()
|
||||
|
||||
for year in range(2020, 2030):
|
||||
date = datetime.date(year, 1, 1)
|
||||
with freezegun.freeze_time(date):
|
||||
login(app)
|
||||
resp = app.get('/manage/resource/%s/%s/week/01/' % (resource.pk, date.year))
|
||||
assert resp.text.count('<th></th>') == 1
|
||||
|
||||
|
||||
def test_resource_week_view_event_outside_timeperiod(app, admin_user):
|
||||
middle_day = now().replace(day=15)
|
||||
middle_day = middle_day + datetime.timedelta(days=4 - middle_day.weekday())
|
||||
resource = Resource.objects.create(label='Foo bar')
|
||||
agenda = Agenda.objects.create(label='Agenda', kind='meetings')
|
||||
agenda.resources.add(resource)
|
||||
desk = Desk.objects.create(agenda=agenda, label='Desk')
|
||||
meetingtype = MeetingType.objects.create(agenda=agenda, label='Bar', duration=30)
|
||||
login(app)
|
||||
|
||||
# no time period - no events
|
||||
resp = app.get(
|
||||
'/manage/resource/%s/%d/week/%s/' % (resource.pk, middle_day.year, middle_day.strftime('%W'))
|
||||
)
|
||||
assert 'No bookings this week.' in resp.text
|
||||
assert 'div class="booking' not in resp.text
|
||||
|
||||
# book some slots
|
||||
for hour, minute in [(9, 0), (17, 0)]:
|
||||
event = Event.objects.create(
|
||||
agenda=agenda,
|
||||
places=1,
|
||||
desk=desk,
|
||||
meeting_type=meetingtype,
|
||||
start_datetime=localtime(now()).replace(
|
||||
day=middle_day.day - middle_day.weekday() + 2, hour=hour, minute=minute
|
||||
),
|
||||
)
|
||||
event.resources.add(resource)
|
||||
Booking.objects.create(event=event)
|
||||
|
||||
# no time period - events are displayed
|
||||
resp = app.get(
|
||||
'/manage/resource/%s/%d/week/%s/' % (resource.pk, middle_day.year, middle_day.strftime('%W'))
|
||||
)
|
||||
assert resp.text.count('div class="booking') == 2
|
||||
|
||||
# events outside time period
|
||||
TimePeriod.objects.create(
|
||||
desk=desk, weekday=2, start_time=datetime.time(10, 0), end_time=datetime.time(16, 0)
|
||||
)
|
||||
resp = app.get(
|
||||
'/manage/resource/%s/%d/week/%s/' % (resource.pk, middle_day.year, middle_day.strftime('%W'))
|
||||
)
|
||||
assert resp.text.count('div class="booking') == 2
|
||||
assert 'Sunday' not in resp.text
|
||||
assert 'Saturday' not in resp.text
|
||||
|
||||
# bookings are cancelled
|
||||
Booking.objects.update(cancellation_datetime=now())
|
||||
resp = app.get(
|
||||
'/manage/resource/%s/%d/week/%s/' % (resource.pk, middle_day.year, middle_day.strftime('%W'))
|
||||
)
|
||||
assert resp.text.count('div class="booking') == 0
|
||||
|
||||
# create an event on saturday
|
||||
Booking.objects.update(cancellation_datetime=None) # reset
|
||||
middle_day = now().replace(day=15)
|
||||
middle_day = middle_day + datetime.timedelta(days=5 - middle_day.weekday())
|
||||
event = Event.objects.create(
|
||||
agenda=agenda,
|
||||
places=1,
|
||||
desk=desk,
|
||||
meeting_type=meetingtype,
|
||||
start_datetime=localtime(now()).replace(day=middle_day.day, hour=10, minute=0),
|
||||
)
|
||||
event.resources.add(resource)
|
||||
Booking.objects.create(event=event)
|
||||
resp = app.get(
|
||||
'/manage/resource/%s/%d/week/%s/' % (resource.pk, middle_day.year, middle_day.strftime('%W'))
|
||||
)
|
||||
assert resp.text.count('div class="booking') == 3
|
||||
assert 'Sunday' not in resp.text
|
||||
assert 'Saturday' in resp.text
|
||||
# bookings are cancelled
|
||||
Booking.objects.update(cancellation_datetime=now())
|
||||
resp = app.get(
|
||||
'/manage/resource/%s/%d/week/%s/' % (resource.pk, middle_day.year, middle_day.strftime('%W'))
|
||||
)
|
||||
assert resp.text.count('div class="booking') == 0
|
||||
# and a timeperiod
|
||||
Booking.objects.update(cancellation_datetime=None) # reset
|
||||
TimePeriod.objects.create(
|
||||
desk=desk, weekday=5, start_time=datetime.time(11, 0), end_time=datetime.time(12, 0)
|
||||
)
|
||||
resp = app.get(
|
||||
'/manage/resource/%s/%d/week/%s/' % (resource.pk, middle_day.year, middle_day.strftime('%W'))
|
||||
)
|
||||
assert resp.text.count('div class="booking') == 3
|
||||
assert 'Sunday' not in resp.text
|
||||
assert 'Saturday' in resp.text
|
||||
|
||||
# create an event on sunday
|
||||
middle_day = now().replace(day=15)
|
||||
middle_day = middle_day + datetime.timedelta(days=6 - middle_day.weekday())
|
||||
event = Event.objects.create(
|
||||
agenda=agenda,
|
||||
places=1,
|
||||
desk=desk,
|
||||
meeting_type=meetingtype,
|
||||
start_datetime=localtime(now()).replace(day=middle_day.day, hour=10, minute=0),
|
||||
)
|
||||
event.resources.add(resource)
|
||||
Booking.objects.create(event=event)
|
||||
resp = app.get(
|
||||
'/manage/resource/%s/%d/week/%s/' % (resource.pk, middle_day.year, middle_day.strftime('%W'))
|
||||
)
|
||||
assert resp.text.count('div class="booking') == 4
|
||||
assert 'Sunday' in resp.text
|
||||
assert 'Saturday' in resp.text
|
||||
# bookings are cancelled
|
||||
Booking.objects.update(cancellation_datetime=now())
|
||||
resp = app.get(
|
||||
'/manage/resource/%s/%d/week/%s/' % (resource.pk, middle_day.year, middle_day.strftime('%W'))
|
||||
)
|
||||
assert resp.text.count('div class="booking') == 0
|
||||
# and a timeperiod
|
||||
Booking.objects.update(cancellation_datetime=None) # reset
|
||||
TimePeriod.objects.create(
|
||||
desk=desk, weekday=6, start_time=datetime.time(11, 0), end_time=datetime.time(12, 0)
|
||||
)
|
||||
resp = app.get(
|
||||
'/manage/resource/%s/%d/week/%s/' % (resource.pk, middle_day.year, middle_day.strftime('%W'))
|
||||
)
|
||||
assert resp.text.count('div class="booking') == 4
|
||||
assert 'Sunday' in resp.text
|
||||
assert 'Saturday' in resp.text
|
||||
|
||||
|
||||
def test_week_view_resource_as_manager(app, manager_user):
|
||||
agenda = Agenda.objects.create(label='Foo Bar', kind='meetings')
|
||||
agenda.view_role = manager_user.groups.all()[0]
|
||||
agenda.save()
|
||||
resource = Resource.objects.create(label='Resource 1')
|
||||
app = login(app, username='manager', password='manager')
|
||||
today = datetime.date.today()
|
||||
app.get('/manage/resource/%s/%d/week/%s/' % (resource.pk, today.year, today.strftime('%W')), status=403)
|
||||
|
||||
|
||||
@freezegun.freeze_time('2020-06-15')
|
||||
def test_resource_month_view(app, admin_user, get_proper_html_str):
|
||||
resource = Resource.objects.create(label='Foo bar')
|
||||
|
@ -261,7 +551,7 @@ def test_resource_month_view(app, admin_user, get_proper_html_str):
|
|||
today = datetime.date.today()
|
||||
with CaptureQueriesContext(connection) as ctx:
|
||||
resp = app.get('/manage/resource/%s/%s/%s/' % (resource.pk, today.year, today.month))
|
||||
assert len(ctx.captured_queries) == 8
|
||||
assert len(ctx.captured_queries) == 9
|
||||
assert resp.text.count('<div class="booking" style="height:33.0%;') == 2 # booking cells
|
||||
assert resp.pyquery.find('div.booking a').not_('.cancel')[0].text.strip() == 'booked'
|
||||
assert resp.pyquery.find('div.booking a').not_('.cancel')[1].text.strip() == "foo - bar's"
|
||||
|
|
Loading…
Reference in New Issue