diff --git a/aleksis/apps/chronos/settings.py b/aleksis/apps/chronos/settings.py new file mode 100644 index 0000000000000000000000000000000000000000..1ae08d71d21171078752c8f2d80b719b2668e4cc --- /dev/null +++ b/aleksis/apps/chronos/settings.py @@ -0,0 +1,8 @@ +from django.utils.translation import gettext_lazy as _ + +CONSTANCE_CONFIG = { + "CHRONOS_SUBSTITUTIONS_PRINT_DAY_NUMBER": (2, _("Number of days shown on substitutions print view")), +} +CONSTANCE_CONFIG_FIELDSETS = { + "Chronos settings": ("CHRONOS_SUBSTITUTIONS_PRINT_DAY_NUMBER",), +} diff --git a/aleksis/apps/chronos/static/css/chronos/timetable.css b/aleksis/apps/chronos/static/css/chronos/timetable.css index c10a7c1942a4e7585d3700f97bc73046ca1b9df1..324272585c7a0447c8f2e901fafbfb7be94dfa7a 100644 --- a/aleksis/apps/chronos/static/css/chronos/timetable.css +++ b/aleksis/apps/chronos/static/css/chronos/timetable.css @@ -96,3 +96,15 @@ table.substitutions td, table.substitutions th { margin: 1%; width: 30%; } + +.print-body table.substitutions td, .print-body table.substitutions th { + padding: 0 2px; +} + +.print-body span.badge.new { + font-size: 0.9rem; + line-height: 20px; + height: 20px; + margin: 2px; + letter-spacing: 0.3pt; +} diff --git a/aleksis/apps/chronos/templates/chronos/substitutions.html b/aleksis/apps/chronos/templates/chronos/substitutions.html index 2d0c99044c421e22d9bea5a3ac66733ee471c7fa..32e98c56d705fc815f709a7cbcc063c5206cb191 100644 --- a/aleksis/apps/chronos/templates/chronos/substitutions.html +++ b/aleksis/apps/chronos/templates/chronos/substitutions.html @@ -17,16 +17,10 @@ <h4>{% trans "Substitutions" %}</h4> </div> <div class="col s2 m6 right align-right print-icon"> - {# <a class="waves-effect waves-teal btn-flat btn-flat-medium right"#} - {# href="#} - {# {% if debug %}#} - {# {% url "timetable_substitutions_pdf_date" date|date:"Y-m-d" %}#} - {# {% else %}#} - {# {% url "timetable_substitutions_pdf" %}#} - {# {% endif %}#} - {# ">#} - {# <i class="material-icons center">print</i>#} - {# </a>#} + <a class="waves-effect waves-teal btn-flat btn-flat-medium right" + href="{% url "substitutions_print_by_date" day.year day.month day.day %}" target="_blank"> + <i class="material-icons center">print</i> + </a> </div> </div> @@ -79,7 +73,8 @@ </td> {% endif %} {% for sub in substitutions %} - <tr class="{% if sub.type_ == "cancellation" %}green-text{% else %}black-text{% endif %}"> {# TODO: Extend support for blue and purple (supervisions and events) #} + <tr class="{% if sub.type_ == "cancellation" %}green-text{% else %}black-text{% endif %}"> + {# TODO: Extend support for blue and purple (supervisions and events) #} <td> {% include "chronos/partials/groups.html" with groups=sub.lesson_period.lesson.groups.all %} </td> @@ -102,7 +97,7 @@ {# TODO: Support other cases#} <span class="badge new green hide-on-med-and-up">{% trans "Cancelled" %}</span> {% endif %} -{# <em>{{ sub.text|default:"" }}</em>#} + {# <em>{{ sub.text|default:"" }}</em>#} </td> <td class="hide-on-small-and-down"> {% if sub.cancelled %} diff --git a/aleksis/apps/chronos/templates/chronos/substitutions_print.html b/aleksis/apps/chronos/templates/chronos/substitutions_print.html index 9f30bd141cb846f71b88e5fb3cb6a9e766ecf271..2a4e474bb2fc407f1297efb754d984140fc30fd0 100644 --- a/aleksis/apps/chronos/templates/chronos/substitutions_print.html +++ b/aleksis/apps/chronos/templates/chronos/substitutions_print.html @@ -1,111 +1,98 @@ {# -*- engine:django -*- #} -{% extends 'core/base.html' %} -{% load common %} +{% extends 'core/base_print.html' %} -{% block content %} -<script type="text/javascript"> - var dest = Urls.substitutions(); -</script> +{% load i18n static %} -<style> - table.substitutions td, table.substitutions th { - padding: 0 2px; - } +{% block extra_head %} + <link rel="stylesheet" href="{% static 'css/chronos/timetable.css' %}"> +{% endblock %} - span.badge.new { - font-size: 0.9rem; - line-height: 20px; - height: 20px; - margin: 2px; - letter-spacing: 0.3pt; - } -</style> +{% block browser_title %}{% blocktrans %}Print: Substitutions{% endblocktrans %}{% endblock %} +{% block page_title %}{% blocktrans %}Substitutions{% endblocktrans %}{% endblock %} -{% for c in days %} - <h4>Substitutions {{ c.date|date" }}</h4> +{% block content %} + {% for day, c in days.items %} + <h4>{% trans "Substitutions" %} {{ c.day|date:"l" }} {{ c.day }}</h4> - {% include "timetable/hintsinsubprint.html" %} + {# {% include "timetable/hintsinsubprint.html" %}#} - <div style="margin-bottom: 20px"> - {% if c.header_info.is_box_needed %} - {% for row in c.header_info.rows %} - <div class="row no-margin"> - <div class="col s3 no-padding"> - <strong>{{ row.0 }}</strong> - </div> - <div class="col s9 no-padding"> - {{ row.1 }} - </div> - </div> - {% endfor %} - {% endif %} - </div> + {# <div style="margin-bottom: 20px">#} + {# {% if c.header_info.is_box_needed %}#} + {# {% for row in c.header_info.rows %}#} + {# <div class="row no-margin">#} + {# <div class="col s3 no-padding">#} + {# <strong>{{ row.0 }}</strong>#} + {# </div>#} + {# <div class="col s9 no-padding">#} + {# {{ row.1 }}#} + {# </div>#} + {# </div>#} + {# {% endfor %}#} + {# {% endif %}#} + {# </div>#} <table class="substitutions"> - <thead> - <tr> - <th><i class="material-icons">people</i></th> - <th><i class="material-icons">access_time</i></th> - <th>{% blocktrans %}Teachers{% endblocktrans %}</th> - <th>{% blocktrans %}Subject{% endblocktrans %}</th> - <th>{% blocktrans %}Room{% endblocktrans %}</th> - <th>{% blocktrans %}Hint{% endblocktrans %}</th> - <th></th> - </tr> - </thead> - <tbody> - {% if not c.sub_table %} - <td colspan="7"> - <p class="flow-text center"> - {% blocktrans %}No existing substitutions{% endblocktrans %} - </p> - </td> - {% endif %} - - {% set color_background = 1 %} - {% set last_classes = "" %} + <thead> + <tr> + <th><i class="material-icons">people</i></th> + <th><i class="material-icons">access_time</i></th> + <th>{% blocktrans %}Teachers{% endblocktrans %}</th> + <th>{% blocktrans %}Subject{% endblocktrans %}</th> + <th>{% blocktrans %}Room{% endblocktrans %}</th> + <th>{% blocktrans %}Notes{% endblocktrans %}</th> + <th></th> + </tr> + </thead> - {% for sub in c.sub_table %} + {% if not c.substitutions %} + <tbody> + <tr class="striped"> + <td colspan="7"> + <p class="flow-text center"> + {% blocktrans %}No substitutions available.{% endblocktrans %} + </p> + </td> + </tr> + </tbody> + {% endif %} - {# Color groups of classes in grey/white #} - {% if last_classes != sub.classes %} - {% if color_background %}{% set color_background = 0 %} - {% else %}{% set color_background = 1 %} - {% endif %} + <tbody> + {% for sub in c.substitutions %} + <tr class="{% if sub.type_ == "cancellation" %}green-text{% else %}black-text{% endif %} "> + <td> + {% include "chronos/partials/groups.html" with groups=sub.lesson_period.lesson.groups.all %} + </td> + <td> + <strong> + {{ sub.lesson_period.period.period }}. + </strong> + </td> + <td> + {% include "chronos/partials/subs/teachers.html" %} + </td> + <td> + {% include "chronos/partials/subs/subject.html" %} + </td> + <td> + {% include "chronos/partials/subs/room.html" %} + </td> + <td> + {% if sub.cancelled %} + {# TODO: Support other cases#} + <span class="badge new green">{% trans "Cancelled" %}</span> {% endif %} - {% set last_classes = sub.classes %} - + {# <em>{{ sub.text|default:"" }}</em>#} + </td> + </tr> - <tr class="{{ sub.color }}-text {% if color_background %}striped{% endif %}"> - <td> - {{ sub.classes }} - </td> - <td> - <strong> - {{ sub.lesson }} - </strong> - </td> - <td> - {% include "timetable/subs/teacher.html" %} - </td> - <td> - {% include "timetable/subs/subject.html" %} - </td> - <td> - {% include "timetable/subs/room.html" %} - </td> - <td> - {% if sub.badge %} - <span class="badge new green">{{ sub.badge }}</span> - {% endif %} - <em>{{ sub.text|default:"" }}</em> - </td> - </tr> - {% endfor %} - </tbody> + {% ifchanged sub.lesson_period.lesson.groups %} + </tbody> + <tbody class="{% cycle "not-striped" "striped" %}"> + {% endifchanged %} + {% endfor %} + </tbody> </table> - -{% endfor %} + {% endfor %} {% endblock %} diff --git a/aleksis/apps/chronos/urls.py b/aleksis/apps/chronos/urls.py index fb3e7c2e0fe25027493b3d5fcf6c2816846c68a3..d5311f492f6592dfb66f4fa5b03b48fc76126188 100644 --- a/aleksis/apps/chronos/urls.py +++ b/aleksis/apps/chronos/urls.py @@ -22,5 +22,7 @@ urlpatterns = [ name="delete_substitution", ), path("substitutions/", views.substitutions, name="substitutions"), + path("substitutions/print/", views.substitutions, {"is_print": True}, name="substitutions_print"), path("substitutions/<int:year>/<int:month>/<int:day>/", views.substitutions, name="substitutions_by_date"), + path("substitutions/<int:year>/<int:month>/<int:day>/print/", views.substitutions, {"is_print": True}, name="substitutions_print_by_date"), ] diff --git a/aleksis/apps/chronos/views.py b/aleksis/apps/chronos/views.py index 66ddde4a514ac2019b55dd4855b7886554a22356..388307c0a01ba3bcde067d456ea41b6348ed1223 100644 --- a/aleksis/apps/chronos/views.py +++ b/aleksis/apps/chronos/views.py @@ -2,6 +2,7 @@ from collections import OrderedDict from datetime import date, datetime, timedelta from typing import Optional, Tuple +from constance import config from django.contrib.auth.decorators import login_required from django.db.models import Count from django.http import HttpRequest, HttpResponse, HttpResponseNotFound @@ -298,6 +299,7 @@ def substitutions( year: Optional[int] = None, month: Optional[int] = None, day: Optional[int] = None, + is_print: bool = False, ) -> HttpResponse: context = {} @@ -307,17 +309,36 @@ def substitutions( else: wanted_day = get_next_relevant_day(timezone.now().date(), datetime.now().time()) - substitutions = LessonSubstitution.objects.on_day(wanted_day) + day_number = config.CHRONOS_SUBSTITUTIONS_PRINT_DAY_NUMBER + day_contexts = {} - context["substitutions"] = substitutions - context["day"] = wanted_day - context["datepicker"] = { - "date": date_unix(wanted_day), - "dest": reverse("substitutions") - } + if is_print: + next_day = wanted_day + for i in range(day_number): + day_contexts[next_day] = {"day": next_day} + next_day = get_next_relevant_day(next_day + timedelta(days=1)) + else: + day_contexts = {wanted_day: {"day": wanted_day}} + + for day in day_contexts: + day_contexts[day]["substitutions"] = LessonSubstitution.objects.on_day( + day + ).order_by("lesson_period__lesson__groups", "lesson_period__period") + + if not is_print: + context = day_contexts[wanted_day] + context["datepicker"] = { + "date": date_unix(wanted_day), + "dest": reverse("substitutions"), + } + + context["url_prev"], context["url_next"] = get_prev_next_by_day( + wanted_day, "substitutions_by_date" + ) - context["url_prev"], context["url_next"] = get_prev_next_by_day( - wanted_day, "substitutions_by_date" - ) + template_name = "chronos/substitutions.html" + else: + context["days"] = day_contexts + template_name = "chronos/substitutions_print.html" - return render(request, "chronos/substitutions.html", context) + return render(request, template_name, context)