0001-agenda-option-to-disable-check-update-when-event-is-.patch
chrono/agendas/migrations/0089_agenda_event_display_template.py | ||
---|---|---|
2 | 2 | |
3 | 3 |
from django.db import migrations, models |
4 | 4 | |
5 |
import chrono.agendas.models |
|
6 | ||
5 | 7 | |
6 | 8 |
class Migration(migrations.Migration): |
7 | 9 | |
... | ... | |
15 | 17 |
name='event_display_template', |
16 | 18 |
field=models.CharField( |
17 | 19 |
blank=True, |
18 |
help_text='By default event labels will be displayed to users. This allows for a custom template to include additional informations. For example, "{{ event.label }} - {{ event.start_datetime }}" will show event datetime after label. Available variables: event.label (label), event.start_datetime (start date/time), event.places (places), event.remaining_places (remaining places), event.duration (duration), event.pricing (pricing).', |
|
20 |
help_text=( |
|
21 |
'By default event labels will be displayed to users. ' |
|
22 |
'This allows for a custom template to include additional informations. ' |
|
23 |
'For example, "{{ event.label }} - {{ event.start_datetime }}" will show event datetime after label. ' |
|
24 |
'Available variables: event.label (label), event.start_datetime (start date/time), event.places (places), ' |
|
25 |
'event.remaining_places (remaining places), event.duration (duration), event.pricing (pricing).' |
|
26 |
), |
|
19 | 27 |
max_length=256, |
28 |
validators=[chrono.agendas.models.event_template_validator], |
|
20 | 29 |
verbose_name='Event display template', |
21 | 30 |
), |
22 | 31 |
), |
chrono/agendas/migrations/0096_checked.py | ||
---|---|---|
1 |
from django.db import migrations, models |
|
2 | ||
3 | ||
4 |
class Migration(migrations.Migration): |
|
5 | ||
6 |
dependencies = [ |
|
7 |
('agendas', '0095_checked'), |
|
8 |
] |
|
9 | ||
10 |
operations = [ |
|
11 |
migrations.AddField( |
|
12 |
model_name='agenda', |
|
13 |
name='disable_check_update', |
|
14 |
field=models.BooleanField( |
|
15 |
default=False, verbose_name='Prevent the check of bookings when event was marked as checked' |
|
16 |
), |
|
17 |
), |
|
18 |
] |
chrono/agendas/models.py | ||
---|---|---|
222 | 222 |
mark_event_checked_auto = models.BooleanField( |
223 | 223 |
_('Automatically mark event as checked when all bookings have been checked'), default=False |
224 | 224 |
) |
225 |
disable_check_update = models.BooleanField( |
|
226 |
_('Prevent the check of bookings when event was marked as checked'), default=False |
|
227 |
) |
|
225 | 228 |
booking_check_filters = models.CharField( |
226 | 229 |
_('Filters'), |
227 | 230 |
max_length=250, |
chrono/api/views.py | ||
---|---|---|
1610 | 1610 |
status=status.HTTP_400_BAD_REQUEST, |
1611 | 1611 |
) |
1612 | 1612 | |
1613 |
if ( |
|
1614 |
self.booking.event.checked |
|
1615 |
and self.booking.event.agenda.disable_check_update |
|
1616 |
and ('user_was_present' in request.data or 'user_absence_reason' in request.data) |
|
1617 |
): |
|
1618 |
return Response( |
|
1619 |
{ |
|
1620 |
'err': 5, |
|
1621 |
'err_class': 'event is marked as checked', |
|
1622 |
'err_desc': _('event is marked as checked'), |
|
1623 |
'errors': serializer.errors, |
|
1624 |
}, |
|
1625 |
status=status.HTTP_400_BAD_REQUEST, |
|
1626 |
) |
|
1627 | ||
1613 | 1628 |
if 'extra_data' in serializer.validated_data: |
1614 | 1629 |
extra_data = self.booking.extra_data or {} |
1615 | 1630 |
extra_data.update(serializer.validated_data['extra_data'] or {}) |
chrono/manager/forms.py | ||
---|---|---|
837 | 837 |
'booking_check_filters', |
838 | 838 |
'booking_user_block_template', |
839 | 839 |
'mark_event_checked_auto', |
840 |
'disable_check_update', |
|
840 | 841 |
] |
841 | 842 |
widgets = {'booking_user_block_template': forms.Textarea(attrs={'rows': 3})} |
842 | 843 |
chrono/manager/templates/chrono/manager_event_check.html | ||
---|---|---|
38 | 38 |
</tr> |
39 | 39 |
{% endif %} |
40 | 40 |
{% if booked_without_status %} |
41 |
{% if not event.checked or not agenda.disable_check_update %} |
|
41 | 42 |
<tr class="booking all-bookings"> |
42 | 43 |
<td colspan="2"><b>{% trans "Mark all bookings without status:" %}</b></td> |
43 | 44 |
<td class="booking-actions"> |
... | ... | |
60 | 61 |
</form> |
61 | 62 |
</td> |
62 | 63 |
</tr> |
64 |
{% endif %} |
|
63 | 65 |
{% endif %} |
64 | 66 |
{% for booking in booked %} |
65 | 67 |
<tr class="booking"> |
chrono/manager/templates/chrono/manager_event_check_booking_fragment.html | ||
---|---|---|
7 | 7 |
({{ booking.user_absence_reason }}) |
8 | 8 |
{% endif %} |
9 | 9 |
</td> |
10 |
{% if not event.checked or not agenda.disable_check_update %} |
|
10 | 11 |
<td class="booking-actions" data-booking-id="{{ booking.id }}"> |
11 | 12 |
<form method="post" action="{% url 'chrono-manager-booking-presence' pk=agenda.pk booking_pk=booking.pk %}" class="with-ajax"> |
12 | 13 |
{% csrf_token %} |
... | ... | |
30 | 31 |
</script> |
31 | 32 |
</form> |
32 | 33 |
</td> |
34 |
{% endif %} |
chrono/manager/templates/chrono/manager_events_agenda_settings.html | ||
---|---|---|
35 | 35 |
<a rel="popup" class="button" href="{% url 'chrono-manager-agenda-booking-check-settings' pk=object.pk %}">{% trans 'Configure' %}</a> |
36 | 36 |
</h3> |
37 | 37 |
<div> |
38 |
<ul> |
|
38 | 39 |
{% if has_absence_reasons %} |
39 | 40 |
{% if agenda.absence_reasons_group %} |
40 |
<p>{% trans "Absence reasons group:" %} {{ agenda.absence_reasons_group }}</p> |
|
41 |
<ul> |
|
42 |
{% for reason in agenda.absence_reasons_group.absence_reasons.all %} |
|
43 |
<li>{{ reason }}</li> |
|
44 |
{% endfor %} |
|
45 |
</ul> |
|
41 |
<li>{% trans "Absence reasons group:" %} {{ agenda.absence_reasons_group }} |
|
42 |
<ul> |
|
43 |
{% for reason in agenda.absence_reasons_group.absence_reasons.all %} |
|
44 |
<li>{{ reason }}</li> |
|
45 |
{% endfor %} |
|
46 |
</ul> |
|
47 |
</li> |
|
46 | 48 |
{% else %} |
47 |
<p>{% trans "No absence reasons configured for this agenda." %}</p>
|
|
49 |
<li>{% trans "No absence reasons configured for this agenda." %}</li>
|
|
48 | 50 |
{% endif %} |
49 | 51 |
{% endif %} |
50 | 52 | |
51 | 53 |
{% with agenda.get_booking_check_filters as check_filters %} |
52 | 54 |
{% if check_filters %} |
53 |
<p>{% trans "Filters:" %}</p> |
|
54 |
<ul> |
|
55 |
{% for key in check_filters %} |
|
56 |
<li>{{ key }}</li> |
|
57 |
{% endfor %} |
|
58 |
</ul> |
|
55 |
<li>{% trans "Filters:" %} |
|
56 |
<ul> |
|
57 |
{% for key in check_filters %} |
|
58 |
<li>{{ key }}</li> |
|
59 |
{% endfor %} |
|
60 |
</ul> |
|
61 |
</li> |
|
59 | 62 |
{% else %} |
60 |
<p>{% trans "No filters configured for this agenda." %}</p>
|
|
63 |
<li>{% trans "No filters configured for this agenda." %}</li>
|
|
61 | 64 |
{% endif %} |
62 | 65 |
{% endwith %} |
63 | 66 | |
64 |
<p>{% trans "User block template:" %}</p> |
|
65 |
<pre>{{ agenda.get_booking_user_block_template }}</pre> |
|
67 |
<li> |
|
68 |
{% trans "User block template:" %} |
|
69 |
<pre>{{ agenda.get_booking_user_block_template }}</pre> |
|
70 |
</li> |
|
66 | 71 | |
67 |
<p>{% trans "Automatically mark events when they are checked:" %} {{ agenda.mark_event_checked_auto|yesno }}</p> |
|
72 |
<li>{% trans "Automatically mark event as checked when all bookings have been checked:" %} {{ agenda.mark_event_checked_auto|yesno }}</li> |
|
73 |
<li>{% trans "Prevent the check of bookings when event was marked as checked:" %} {{ agenda.disable_check_update|yesno }}</li> |
|
74 |
</ul> |
|
68 | 75 |
</div> |
69 | 76 |
</div> |
70 | 77 |
chrono/manager/views.py | ||
---|---|---|
1995 | 1995 |
) |
1996 | 1996 |
self.event = get_object_or_404( |
1997 | 1997 |
Event, |
1998 |
Q(checked=False) | Q(agenda__disable_check_update=False), |
|
1998 | 1999 |
pk=kwargs.get('event_pk'), |
1999 | 2000 |
agenda=self.agenda, |
2000 | 2001 |
start_datetime__date__lte=now().date(), |
... | ... | |
2734 | 2735 |
def get_booking(self, **kwargs): |
2735 | 2736 |
return get_object_or_404( |
2736 | 2737 |
Booking, |
2738 |
Q(event__checked=False) | Q(event__agenda__disable_check_update=False), |
|
2737 | 2739 |
pk=kwargs['booking_pk'], |
2738 | 2740 |
event__agenda=self.agenda, |
2739 | 2741 |
event__start_datetime__date__lte=now().date(), |
tests/api/test_booking.py | ||
---|---|---|
448 | 448 |
other_booking.refresh_from_db() |
449 | 449 |
assert other_booking.user_was_present is None # not changed |
450 | 450 | |
451 |
# mark the event as checked |
|
452 |
event.checked = True |
|
453 |
event.save() |
|
454 |
resp = app.patch_json('/api/booking/%s/' % booking.pk, params={'user_was_present': flag}) |
|
455 |
assert resp.json['err'] == 0 |
|
456 | ||
457 |
# now disable check update |
|
458 |
agenda.disable_check_update = True |
|
459 |
agenda.save() |
|
460 |
resp = app.patch_json('/api/booking/%s/' % booking.pk, params={'user_was_present': flag}, status=400) |
|
461 |
assert resp.json['err'] == 5 |
|
462 |
assert resp.json['err_desc'] == 'event is marked as checked' |
|
463 |
resp = app.patch_json('/api/booking/%s/' % booking.pk) |
|
464 |
assert resp.json['err'] == 0 |
|
465 | ||
451 | 466 | |
452 | 467 |
def test_booking_patch_api_absence_reason(app, user): |
453 | 468 |
agenda = Agenda.objects.create(kind='events') |
... | ... | |
514 | 529 |
other_booking.refresh_from_db() |
515 | 530 |
assert other_booking.user_absence_reason == '' # not changed |
516 | 531 | |
532 |
# mark the event as checked |
|
533 |
event.checked = True |
|
534 |
event.save() |
|
535 |
resp = app.patch_json('/api/booking/%s/' % booking.pk, params={'user_absence_reason': reason.slug}) |
|
536 |
assert resp.json['err'] == 0 |
|
537 | ||
538 |
# now disable check update |
|
539 |
agenda.disable_check_update = True |
|
540 |
agenda.save() |
|
541 |
resp = app.patch_json( |
|
542 |
'/api/booking/%s/' % booking.pk, params={'user_absence_reason': reason.slug}, status=400 |
|
543 |
) |
|
544 |
assert resp.json['err'] == 5 |
|
545 |
assert resp.json['err_desc'] == 'event is marked as checked' |
|
546 |
resp = app.patch_json('/api/booking/%s/' % booking.pk) |
|
547 |
assert resp.json['err'] == 0 |
|
548 | ||
517 | 549 | |
518 | 550 |
def test_booking_patch_api_extra_data(app, user): |
519 | 551 |
agenda = Agenda.objects.create(kind='events') |
tests/manager/test_all.py | ||
---|---|---|
570 | 570 |
agenda.refresh_from_db() |
571 | 571 |
assert agenda.mark_event_checked_auto is True |
572 | 572 | |
573 |
# check disable check |
|
574 |
assert agenda.disable_check_update is False |
|
575 |
resp = app.get(url) |
|
576 |
resp.form['disable_check_update'] = True |
|
577 |
resp = resp.form.submit() |
|
578 |
agenda.refresh_from_db() |
|
579 |
assert agenda.disable_check_update is True |
|
580 | ||
573 | 581 |
# check kind |
574 | 582 |
agenda.kind = 'meetings' |
575 | 583 |
agenda.save() |
tests/manager/test_event.py | ||
---|---|---|
1385 | 1385 |
assert booking.user_was_present is True |
1386 | 1386 |
assert booking.user_absence_reason == '' |
1387 | 1387 | |
1388 |
# mark the event as checked |
|
1389 |
event.checked = True |
|
1390 |
event.save() |
|
1391 |
resp = app.get('/manage/agendas/%s/events/%s/check' % (agenda.pk, event.pk)) |
|
1392 |
assert '/manage/agendas/%s/bookings/%s/presence' % (agenda.pk, booking.pk) in resp |
|
1393 |
assert '/manage/agendas/%s/bookings/%s/absence' % (agenda.pk, booking.pk) in resp |
|
1394 |
resp = app.post( |
|
1395 |
'/manage/agendas/%s/bookings/%s/absence' % (agenda.pk, booking.pk), |
|
1396 |
params={'csrfmiddlewaretoken': token}, |
|
1397 |
status=302, |
|
1398 |
) |
|
1399 |
app.post( |
|
1400 |
'/manage/agendas/%s/bookings/%s/presence' % (agenda.pk, booking.pk), |
|
1401 |
params={'csrfmiddlewaretoken': token}, |
|
1402 |
status=302, |
|
1403 |
) |
|
1404 | ||
1405 |
# now disable check update |
|
1406 |
agenda.disable_check_update = True |
|
1407 |
agenda.save() |
|
1408 |
resp = app.get('/manage/agendas/%s/events/%s/check' % (agenda.pk, event.pk)) |
|
1409 |
assert '/manage/agendas/%s/bookings/%s/presence' % (agenda.pk, booking.pk) not in resp |
|
1410 |
assert '/manage/agendas/%s/bookings/%s/absence' % (agenda.pk, booking.pk) not in resp |
|
1411 |
resp = app.post( |
|
1412 |
'/manage/agendas/%s/bookings/%s/absence' % (agenda.pk, booking.pk), |
|
1413 |
params={'csrfmiddlewaretoken': token}, |
|
1414 |
status=404, |
|
1415 |
) |
|
1416 |
app.post( |
|
1417 |
'/manage/agendas/%s/bookings/%s/presence' % (agenda.pk, booking.pk), |
|
1418 |
params={'csrfmiddlewaretoken': token}, |
|
1419 |
status=404, |
|
1420 |
) |
|
1421 | ||
1388 | 1422 | |
1389 | 1423 |
def test_event_check_booking_ajax(app, admin_user): |
1390 | 1424 |
group = AbsenceReasonGroup.objects.create(label='Foo bar') |
... | ... | |
1482 | 1516 |
event.refresh_from_db() |
1483 | 1517 |
assert event.checked is True |
1484 | 1518 | |
1519 |
# event is checked |
|
1485 | 1520 |
booking3 = Booking.objects.create(event=event, user_first_name='User', user_last_name='51') |
1521 |
resp = app.get('/manage/agendas/%s/events/%s/check' % (agenda.pk, event.pk)) |
|
1522 |
assert 'Mark all bookings without status' in resp |
|
1486 | 1523 |
app.post( |
1487 | 1524 |
'/manage/agendas/%s/events/%s/absence' % (agenda.pk, event.pk), |
1488 | 1525 |
params={'csrfmiddlewaretoken': token, 'reason': 'Foo reason'}, |
... | ... | |
1496 | 1533 |
booking3.refresh_from_db() |
1497 | 1534 |
assert booking3.user_was_present is False |
1498 | 1535 |
assert booking3.user_absence_reason == 'Foo reason' |
1536 | ||
1537 |
# now disable check update |
|
1538 |
agenda.disable_check_update = True |
|
1539 |
agenda.save() |
|
1540 |
Booking.objects.create(event=event, user_first_name='User', user_last_name='52') |
|
1541 |
resp = app.get('/manage/agendas/%s/events/%s/check' % (agenda.pk, event.pk)) |
|
1542 |
assert 'Mark all bookings without status' not in resp |
|
1543 |
app.post( |
|
1544 |
'/manage/agendas/%s/events/%s/absence' % (agenda.pk, event.pk), |
|
1545 |
params={'csrfmiddlewaretoken': token, 'reason': 'Foo reason'}, |
|
1546 |
status=404, |
|
1547 |
) |
|
1548 |
resp = app.post( |
|
1549 |
'/manage/agendas/%s/events/%s/absence' % (agenda.pk, event.pk), |
|
1550 |
params={'csrfmiddlewaretoken': token}, |
|
1551 |
status=404, |
|
1552 |
) |
|
1499 |
- |