manager: add excluded timeperiods management (#40058)
This commit is contained in:
parent
3aba16e82b
commit
aec5b30fd9
|
@ -150,9 +150,18 @@ class TimePeriodForm(forms.ModelForm):
|
|||
'start_time': widgets.TimeWidget(),
|
||||
'end_time': widgets.TimeWidget(),
|
||||
'desk': forms.HiddenInput(),
|
||||
'agenda': forms.HiddenInput(),
|
||||
}
|
||||
exclude = []
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
has_desk = kwargs.pop('has_desk')
|
||||
super(TimePeriodForm, self).__init__(*args, **kwargs)
|
||||
if has_desk:
|
||||
del self.fields['agenda']
|
||||
else:
|
||||
del self.fields['desk']
|
||||
|
||||
def clean_end_time(self):
|
||||
if self.cleaned_data['end_time'] <= self.cleaned_data['start_time']:
|
||||
raise ValidationError(_('End time must come after start time.'))
|
||||
|
|
|
@ -33,7 +33,7 @@
|
|||
{{ form.as_p }}
|
||||
<div class="buttons">
|
||||
<button class="submit-button">{% trans "Save" %}</button>
|
||||
<a class="cancel" href="{% url 'chrono-manager-agenda-settings' pk=desk.agenda.id %}">{% trans 'Cancel' %}</a>
|
||||
<a class="cancel" href="{% url 'chrono-manager-agenda-settings' pk=agenda.id %}">{% trans 'Cancel' %}</a>
|
||||
</div>
|
||||
</form>
|
||||
{% endblock %}
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
{% load i18n %}
|
||||
|
||||
{% block agenda-extra-management-actions %}
|
||||
<a rel="popup" href="{% url 'chrono-manager-virtual-agenda-add-time-period' pk=object.id %}">{% trans 'Add Excluded Period' %}</a>
|
||||
<a rel="popup" href="{% url 'chrono-manager-agenda-add-virtual-member' pk=object.id %}">{% trans 'Include Agenda' %}</a>
|
||||
{% endblock %}
|
||||
|
||||
|
@ -59,5 +60,20 @@
|
|||
</div>
|
||||
{% endif %}
|
||||
|
||||
{% if agenda.excluded_timeperiods.count %}
|
||||
<div class="section">
|
||||
<h3>{% trans 'Excluded Periods' %}</h3>
|
||||
<div>
|
||||
<ul class="objects-list single-links">
|
||||
{% for time_period in agenda.excluded_timeperiods.all %}
|
||||
<li><a rel="popup" href="{% url 'chrono-manager-time-period-edit' pk=time_period.id %}">
|
||||
{{time_period.weekday_str}} / {{time_period.start_time}} → {{time_period.end_time}}</a>
|
||||
<a rel="popup" class="delete" href="{% url 'chrono-manager-time-period-delete' pk=time_period.id %}">{% trans "remove" %}</a>
|
||||
</li>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
{% endblock %}
|
||||
|
|
|
@ -74,6 +74,11 @@ urlpatterns = [
|
|||
views.agenda_add_time_period,
|
||||
name='chrono-manager-agenda-add-time-period',
|
||||
),
|
||||
url(
|
||||
r'^agendas/(?P<pk>\d+)/add-time-period$',
|
||||
views.virtual_agenda_add_time_period,
|
||||
name='chrono-manager-virtual-agenda-add-time-period',
|
||||
),
|
||||
url(r'^timeperiods/(?P<pk>\d+)/edit$', views.time_period_edit, name='chrono-manager-time-period-edit'),
|
||||
url(
|
||||
r'^timeperiods/(?P<pk>\d+)/delete$',
|
||||
|
|
|
@ -680,6 +680,30 @@ class ManagedDeskSubobjectMixin(object):
|
|||
return reverse('chrono-manager-agenda-settings', kwargs={'pk': self.desk.agenda.id})
|
||||
|
||||
|
||||
class ManagedTimePeriodMixin(object):
|
||||
agenda = None
|
||||
|
||||
def dispatch(self, request, *args, **kwargs):
|
||||
self.time_period = self.get_object()
|
||||
self.agenda = self.time_period.agenda
|
||||
self.has_desk = False
|
||||
if self.time_period.desk:
|
||||
self.agenda = self.time_period.desk.agenda
|
||||
self.has_desk = True
|
||||
|
||||
if not self.agenda.can_be_managed(request.user):
|
||||
raise PermissionDenied()
|
||||
return super(ManagedTimePeriodMixin, self).dispatch(request, *args, **kwargs)
|
||||
|
||||
def get_context_data(self, **kwargs):
|
||||
context = super(ManagedTimePeriodMixin, self).get_context_data(**kwargs)
|
||||
context['agenda'] = self.agenda
|
||||
return context
|
||||
|
||||
def get_success_url(self):
|
||||
return reverse('chrono-manager-agenda-settings', kwargs={'pk': self.agenda.id})
|
||||
|
||||
|
||||
class AgendaSettings(ManagedAgendaMixin, DetailView):
|
||||
model = Agenda
|
||||
|
||||
|
@ -891,35 +915,60 @@ class MeetingTypeDeleteView(ManagedAgendaSubobjectMixin, DeleteView):
|
|||
meeting_type_delete = MeetingTypeDeleteView.as_view()
|
||||
|
||||
|
||||
def process_time_period_add_form(form, desk=None, agenda=None):
|
||||
assert desk or agenda, "a time period requires a desk or a agenda"
|
||||
for weekday in form.cleaned_data.get('weekdays'):
|
||||
period = TimePeriod(
|
||||
weekday=weekday,
|
||||
start_time=form.cleaned_data['start_time'],
|
||||
end_time=form.cleaned_data['end_time'],
|
||||
)
|
||||
if desk:
|
||||
period.desk = desk
|
||||
elif agenda:
|
||||
period.agenda = agenda
|
||||
period.save()
|
||||
|
||||
|
||||
class AgendaAddTimePeriodView(ManagedDeskMixin, FormView):
|
||||
template_name = 'chrono/manager_time_period_form.html'
|
||||
form_class = TimePeriodAddForm
|
||||
|
||||
def form_valid(self, form):
|
||||
for weekday in form.cleaned_data.get('weekdays'):
|
||||
period = TimePeriod(
|
||||
weekday=weekday,
|
||||
start_time=form.cleaned_data['start_time'],
|
||||
end_time=form.cleaned_data['end_time'],
|
||||
desk=self.desk,
|
||||
)
|
||||
period.save()
|
||||
process_time_period_add_form(form, desk=self.desk)
|
||||
return super(AgendaAddTimePeriodView, self).form_valid(form)
|
||||
|
||||
|
||||
agenda_add_time_period = AgendaAddTimePeriodView.as_view()
|
||||
|
||||
|
||||
class TimePeriodEditView(ManagedDeskSubobjectMixin, UpdateView):
|
||||
class VirtualAgendaAddTimePeriodView(ManagedAgendaMixin, FormView):
|
||||
template_name = 'chrono/manager_time_period_form.html'
|
||||
form_class = TimePeriodAddForm
|
||||
|
||||
def form_valid(self, form):
|
||||
process_time_period_add_form(form, agenda=self.agenda)
|
||||
return super(VirtualAgendaAddTimePeriodView, self).form_valid(form)
|
||||
|
||||
|
||||
virtual_agenda_add_time_period = VirtualAgendaAddTimePeriodView.as_view()
|
||||
|
||||
|
||||
class TimePeriodEditView(ManagedTimePeriodMixin, UpdateView):
|
||||
template_name = 'chrono/manager_time_period_form.html'
|
||||
model = TimePeriod
|
||||
form_class = TimePeriodForm
|
||||
|
||||
def get_form_kwargs(self):
|
||||
kwargs = super(TimePeriodEditView, self).get_form_kwargs()
|
||||
kwargs['has_desk'] = self.has_desk
|
||||
return kwargs
|
||||
|
||||
|
||||
time_period_edit = TimePeriodEditView.as_view()
|
||||
|
||||
|
||||
class TimePeriodDeleteView(ManagedDeskSubobjectMixin, DeleteView):
|
||||
class TimePeriodDeleteView(ManagedTimePeriodMixin, DeleteView):
|
||||
template_name = 'chrono/manager_confirm_delete.html'
|
||||
model = TimePeriod
|
||||
|
||||
|
|
|
@ -2251,9 +2251,12 @@ def test_virtual_agenda_settings_empty(app, admin_user):
|
|||
assert 'Export' in resp.text
|
||||
assert 'Delete' in resp.text
|
||||
assert 'Included Agendas' in resp.text
|
||||
assert 'Add Excluded Period' in resp.text
|
||||
assert "This virtual agenda doesn't include any agenda yet" in resp.text
|
||||
# No meeting types yet
|
||||
assert 'Meeting Types' not in resp.text
|
||||
# No absence yet
|
||||
assert 'Excluded Periods' not in resp.text
|
||||
|
||||
|
||||
def test_virtual_agenda_settings(app, admin_user):
|
||||
|
@ -2264,7 +2267,9 @@ def test_virtual_agenda_settings(app, admin_user):
|
|||
VirtualMember.objects.create(virtual_agenda=agenda, real_agenda=meeting_agenda_2)
|
||||
MeetingType.objects.create(agenda=meeting_agenda_1, label='MT', slug='mt', duration=10)
|
||||
mt2 = MeetingType.objects.create(agenda=meeting_agenda_2, label='MT', slug='mt', duration=10)
|
||||
|
||||
TimePeriod.objects.create(
|
||||
agenda=agenda, weekday=0, start_time=datetime.time(10, 0), end_time=datetime.time(18, 0)
|
||||
)
|
||||
app = login(app)
|
||||
resp = app.get('/manage/agendas/%s/settings' % agenda.pk)
|
||||
assert "This virtual agenda doesn't include any agenda yet" not in resp.text
|
||||
|
@ -2277,6 +2282,9 @@ def test_virtual_agenda_settings(app, admin_user):
|
|||
assert 'mt' in resp.text
|
||||
assert '10' in resp.text
|
||||
|
||||
assert 'Excluded Periods' in resp.text
|
||||
assert 'Monday' in resp.text
|
||||
|
||||
# Error message when incompatible meeting types
|
||||
mt2.delete()
|
||||
resp = app.get('/manage/agendas/%s/settings' % agenda.pk)
|
||||
|
@ -2307,6 +2315,61 @@ def test_virtual_agenda_settings_include(app, admin_user):
|
|||
assert len(resp.form['real_agenda'].options) == 2
|
||||
|
||||
|
||||
def test_virtual_agenda_settings_add_excluded_period(app, admin_user):
|
||||
agenda = Agenda.objects.create(label='My Virtual agenda', kind='virtual')
|
||||
|
||||
app = login(app)
|
||||
resp = app.get('/manage/agendas/%s/settings' % agenda.pk)
|
||||
resp = resp.click('Add Excluded Period')
|
||||
|
||||
resp.form['weekdays-0'].checked = True
|
||||
resp.form['start_time'] = '10:00'
|
||||
resp.form['end_time'] = '17:00'
|
||||
resp = resp.form.submit()
|
||||
tp = TimePeriod.objects.get(agenda=agenda)
|
||||
assert tp.weekday == 0
|
||||
assert tp.start_time.hour == 10
|
||||
assert tp.start_time.minute == 0
|
||||
assert tp.end_time.hour == 17
|
||||
assert tp.end_time.minute == 0
|
||||
|
||||
resp = resp.follow()
|
||||
assert u'Monday / 10 a.m. → 5 p.m.' in resp.text
|
||||
|
||||
|
||||
def test_virtual_agenda_settings_edit_excluded_period(app, admin_user):
|
||||
agenda = Agenda.objects.create(label='My Virtual agenda', kind='virtual')
|
||||
tp = TimePeriod.objects.create(
|
||||
agenda=agenda, weekday=0, start_time=datetime.time(10, 0), end_time=datetime.time(18, 0)
|
||||
)
|
||||
app = login(app)
|
||||
resp = app.get('/manage/agendas/%s/settings' % agenda.pk)
|
||||
url = '/manage/timeperiods/%s/edit' % tp.pk
|
||||
resp = resp.click(href=url)
|
||||
resp.form['start_time'] = '11:00'
|
||||
resp = resp.form.submit()
|
||||
tp = TimePeriod.objects.get(agenda=agenda)
|
||||
assert tp.weekday == 0
|
||||
assert tp.start_time.hour == 11
|
||||
assert tp.start_time.minute == 0
|
||||
assert tp.end_time.hour == 18
|
||||
assert tp.end_time.minute == 0
|
||||
|
||||
|
||||
def test_virtual_agenda_settings_delete_excluded_period(app, admin_user):
|
||||
agenda = Agenda.objects.create(label='My Virtual agenda', kind='virtual')
|
||||
tp = TimePeriod.objects.create(
|
||||
agenda=agenda, weekday=0, start_time=datetime.time(10, 0), end_time=datetime.time(18, 0)
|
||||
)
|
||||
app = login(app)
|
||||
resp = app.get('/manage/agendas/%s/settings' % agenda.pk)
|
||||
url = '/manage/timeperiods/%s/delete' % tp.pk
|
||||
resp = resp.click(href=url)
|
||||
resp = resp.form.submit()
|
||||
assert resp.location.endswith('/manage/agendas/%s/settings' % agenda.id)
|
||||
assert TimePeriod.objects.count() == 0
|
||||
|
||||
|
||||
def test_virtual_agenda_settings_include_incompatible_agenda(app, admin_user):
|
||||
agenda = Agenda.objects.create(label='My Virtual agenda', kind='virtual')
|
||||
meeting_agenda_1 = Agenda.objects.create(label='Meeting agenda 1', kind='meetings')
|
||||
|
|
Loading…
Reference in New Issue