diff --git a/CHANGELOG.rst b/CHANGELOG.rst
index 5389a72e60aac898a48868c0cb52fe7241fcec60..c5839dcf73864a97c53e0d84a080124cc221fa5c 100644
--- a/CHANGELOG.rst
+++ b/CHANGELOG.rst
@@ -4,6 +4,11 @@ Changelog
 `1.0a3`_
 --------
 
+New features
+~~~~~~~~~~~~
+
+* Allow to register absences and excuses centrally
+
 Bugfixes
 ~~~~~~~~
 
diff --git a/biscuit/apps/alsijil/forms.py b/biscuit/apps/alsijil/forms.py
index 7912bcf8bccf4e0f4939cb15771010c1ab4ee741..6084cf2bf015b42b937fc20b10c41af3453a8066 100644
--- a/biscuit/apps/alsijil/forms.py
+++ b/biscuit/apps/alsijil/forms.py
@@ -2,6 +2,7 @@ from django import forms
 from django.db.models import Count
 from django.utils.translation import ugettext_lazy as _
 from django_select2.forms import Select2Widget
+from datetime import datetime
 
 from biscuit.apps.chronos.models import Room
 from biscuit.core.models import Group, Person
@@ -47,3 +48,12 @@ class SelectForm(forms.Form):
 
 PersonalNoteFormSet = forms.modelformset_factory(
     PersonalNote, form=PersonalNoteForm, max_num=0, extra=0)
+
+
+class ManageAbsenceForm(forms.Form):
+    date_start = forms.DateField(label=_('Start date'), widget=forms.SelectDateWidget, initial=datetime.today)
+    date_end = forms.DateField(label=_('End date'), widget=forms.SelectDateWidget, initial=datetime.today)
+    starting_lesson = forms.IntegerField(label=_('Starting lesson'), initial=0)
+    person = forms.ModelChoiceField(label=_('Person'), queryset=Person.objects.all(), widget=Select2Widget)
+    absent = forms.BooleanField(label=_('Absent'), initial=True)
+    excused = forms.BooleanField(label=_('Excused'), initial=True)
diff --git a/biscuit/apps/alsijil/menus.py b/biscuit/apps/alsijil/menus.py
index b5389356179362399cdb1e844eb4ae715943bcb8..6184cbe5d54b5193c0050cd316e5a78b769a484a 100644
--- a/biscuit/apps/alsijil/menus.py
+++ b/biscuit/apps/alsijil/menus.py
@@ -17,6 +17,11 @@ MENUS = {
                     'name': _('Current week'),
                     'url': 'week_view',
                     'validators': ['menu_generator.validators.is_authenticated']
+                },
+                {
+                    'name': _('Manage absence'),
+                    'url': 'manage_absence',
+                    'validators': ['menu_generator.validators.is_superuser']
                 }
             ]
         }
diff --git a/biscuit/apps/alsijil/templates/alsijil/manage_absence.html b/biscuit/apps/alsijil/templates/alsijil/manage_absence.html
new file mode 100644
index 0000000000000000000000000000000000000000..16231893fd5975bbea0953a84fbcf57aea3faf44
--- /dev/null
+++ b/biscuit/apps/alsijil/templates/alsijil/manage_absence.html
@@ -0,0 +1,29 @@
+{# -*- engine:django -*- #}
+{% extends "core/base.html" %}
+{% load bootstrap4 i18n static %}
+
+{% block bootstrap4_extra_head %}
+  {{ block.super }}
+  {{ manage_absence_form.media.css }}
+{% endblock %}
+
+{% block bootstrap4_extra_script %}
+  {{ block.super }}
+  {{ manage_absence_form.media.js }}
+{% endblock %}
+
+{% block bootstrap4_title %}{% blocktrans%}Manage absence{% endblocktrans %} - {{ block.super }}{% endblock %}
+
+{% block page_title %}Manage absences{% endblock %}
+
+{% block content %}
+
+  <form method="post">
+    {% csrf_token %}
+    {% bootstrap_form manage_absence_form %}
+    <button type="submit" class="btn btn-dark">
+      {% blocktrans %}Save{% endblocktrans %}
+    </button>
+  </form>
+
+{% endblock %}
diff --git a/biscuit/apps/alsijil/urls.py b/biscuit/apps/alsijil/urls.py
index e8d4c6b254273d10a1152239d9de3bc9ba0bc260..97aa3f4b1d251217419ecd3c520972fe67364d1b 100644
--- a/biscuit/apps/alsijil/urls.py
+++ b/biscuit/apps/alsijil/urls.py
@@ -11,5 +11,7 @@ urlpatterns = [
     path('week/<int:year>/<int:week>', views.week_view,
          name='week_view_by_week'),
     path('print/group/<int:id_>', views.full_register_group,
-         name='full_register_group')
+         name='full_register_group'),
+    path('absences/new', views.manage_absence,
+         name='manage_absence'),
 ]
diff --git a/biscuit/apps/alsijil/views.py b/biscuit/apps/alsijil/views.py
index 497576ce2a1daab1f4a392e3a404cbc52c8c2057..f18dd9d578ba1cd355fab7579d456e1f2dd3c7fc 100644
--- a/biscuit/apps/alsijil/views.py
+++ b/biscuit/apps/alsijil/views.py
@@ -1,4 +1,4 @@
-from datetime import date, datetime
+from datetime import date, datetime, timedelta
 from typing import Optional
 
 from django.contrib.auth.decorators import login_required
@@ -12,8 +12,10 @@ from django.utils.translation import ugettext as _
 from biscuit.apps.chronos.models import LessonPeriod
 from biscuit.apps.chronos.util import CalendarWeek
 from biscuit.core.models import Group, Person
+from biscuit.core.decorators import admin_required
+from biscuit.core.util import messages
 
-from .forms import LessonDocumentationForm, PersonalNoteFormSet, SelectForm
+from .forms import ManageAbsenceForm, LessonDocumentationForm, PersonalNoteFormSet, SelectForm
 from .models import LessonDocumentation
 
 
@@ -202,3 +204,35 @@ def full_register_group(request: HttpRequest, id_: int) -> HttpResponse:
     context['today'] = date.today()
 
     return render(request, 'alsijil/print/full_register.html', context)
+
+
+@admin_required
+def manage_absence(request: HttpRequest) -> HttpResponse:
+    context = {}
+
+    manage_absence_form = ManageAbsenceForm(request.POST or None)
+
+    if request.method == 'POST':
+        if manage_absence_form.is_valid():
+            # Get data from form
+            person = manage_absence_form.cleaned_data['person']
+            start_date = manage_absence_form.cleaned_data['date_start']
+            end_date = manage_absence_form.cleaned_data['date_end']
+            starting_lesson = manage_absence_form.cleaned_data['starting_lesson']
+            absent = manage_absence_form.cleaned_data['absent']
+            excused = manage_absence_form.cleaned_data['excused']
+
+            # Mark person as absent
+            delta = end_date - start_date
+            for i in range(delta.days+1):
+                starting_period = starting_lesson if i == 0 else 0
+                day = start_date + timedelta(days=1)
+                person.mark_absent(day, starting_period=starting_period, absent=absent, excused=excused)
+                person.save()
+
+            messages.success(request, _('The absence has been saved.'))
+            return redirect('index')
+
+    context['manage_absence_form'] = manage_absence_form
+
+    return render(request, 'alsijil/manage_absence.html', context)