diff --git a/ticdesk_events/forms.py b/ticdesk_events/forms.py
index 972b4e1abfa33c70c150fb18d18a8a52a34ee8c5..6fa1e2279f11df6b835a2f240a5472d6dd283667 100644
--- a/ticdesk_events/forms.py
+++ b/ticdesk_events/forms.py
@@ -6,6 +6,8 @@ from localflavor.generic.forms import IBANFormField
 from localflavor.generic.countries.sepa import IBAN_SEPA_COUNTRIES
 import phonenumbers
 
+from .models import Voucher
+
 CHANNEL_CHOICES = [
     ('none', _('Keine Angabe')),
     ('internet', _('Aus dem Internet')),
@@ -41,6 +43,14 @@ def is_phonenumber(number):
     except:
         raise forms.ValidationError(_('%s ist keine gültige Telefonnummer!') % number)
 
+def is_valid_voucher_for(project_cn):
+    def _is_valid_voucher(code):
+        try:
+            voucher = Voucher.objects.get(code=code, project_cn=project_cn, used=False)
+        except Voucher.DoesNotExist:
+            raise forms.ValidationError(_('Der Gutschein-Code ist ungültig.'))
+    return _is_valid_voucher
+
 def clean_phonenumber(field):
     def _clean_phonenumber(obj):
         value = obj.cleaned_data[field]
@@ -89,6 +99,10 @@ class EventRegisterForm(forms.Form):
     channel = forms.ChoiceField(label=_('Wie hast du von der Veranstaltung erfahren?'), choices=CHANNEL_CHOICES)
     comment = forms.CharField(required=False, label=_('Kommentar / Bemerkungen'), widget=forms.Textarea)
 
+    voucher_code = forms.CharField(required=False, label=_('Gutschein-Code'),
+        help_text=_('Wenn du einen Gutschein für die Veranstaltung hast, gib hier den Code ein. Er wird automatisch verrechnet.')
+    )
+
     donation = forms.IntegerField(required=False, min_value=0, label=_('Freiwilliger Mehrbetrag'),
         help_text=_('Unser Verein möchte allen Kindern und Jugendlichen die Möglichkeit bieten, an unseren Veranstaltungen teilzunehmen. Oft ist der Teilnehmerbeitrag für eine Familie jedoch nicht aufzubringen. Wir halten deshalb einen Etat bereit, aus dem wir Teilnahmen fördern können, nachdem wir die Notwendigkeit und Berechtigung sorgfältig geprüft haben. Für diesen Etat sind wir auf Spenden angewiesen. Wenn Sie einen freiwilligen Mehrbetrag für diesen Etat spenden möchten, geben Sie dies bitte hier an. Ob und wenn ja in welcher Höhe gespendet wurde, wird von uns nicht dauerhaft gespeichert und auch nicht innerhalb des Vereins, z.B. an Freizeitbetreuer, weitergegeben.')
     )
@@ -110,6 +124,10 @@ class EventRegisterForm(forms.Form):
     clean_mobile = clean_phonenumber('mobile')
     clean_guardian_mobile = clean_phonenumber('guardian_mobile')
 
+    def __init__(self, project, *args, **kwargs):
+        super(EventRegisterForm, self).__init__(*args, **kwargs)
+        self.fields['voucher_code'].validators.append(is_valid_voucher_for(project.cn))
+
 class EventFeedbackForm(forms.Form):
     comment_private = forms.CharField(required=False, label=_('Kommentar für das Team'),
         help_text=_('Dieser Kommentar ist nur für das Team. Du kannst hier alles aufschreiben, was du uns noch als Feedback mitteilen möchtest.'),
diff --git a/ticdesk_events/migrations/0001_initial.py b/ticdesk_events/migrations/0001_initial.py
new file mode 100644
index 0000000000000000000000000000000000000000..8671ea18f6fa968d98cbbeb6ac83b82d4500c979
--- /dev/null
+++ b/ticdesk_events/migrations/0001_initial.py
@@ -0,0 +1,27 @@
+from __future__ import unicode_literals
+
+from django.db import migrations, models
+import ldapdb.models.fields
+import ticdesk_account.models
+
+
+class Migration(migrations.Migration):
+
+    initial = True
+
+    dependencies = [
+    ]
+
+    operations = [
+        migrations.CreateModel(
+            name='Voucher',
+            fields=[
+                ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
+                ('code', models.CharField(max_length=8, unique=True)),
+                ('project_cn', models.CharField(max_length=50)),
+                ('discount', models.IntegerField(default=100)),
+                ('used', models.BooleanField(default=False)),
+                ('used_person_uid', models.CharField(blank=True, max_length=20, null=True)),
+            ],
+        ),
+    ]
diff --git a/ticdesk_events/models.py b/ticdesk_events/models.py
index 1e0fa158bd5b6166eac9ec18ea79628a9620f6a4..c0b59883985d0ee71b04b7af45e5120a24bce198 100644
--- a/ticdesk_events/models.py
+++ b/ticdesk_events/models.py
@@ -1,11 +1,20 @@
 from datetime import date
 
 from django.apps import apps
+from django.db import models
 from ldapdb.models.fields import CharField, DateField, IntegerField, ListField
 import ldapdb.models
 
 from ticdesk_account.models import TeckidsLdapMixin
 
+class Voucher(models.Model):
+    code = models.CharField(max_length=8, unique=True)
+    project_cn = models.CharField(max_length=50)
+    discount = models.IntegerField(default=100)
+
+    used = models.BooleanField(default=False)
+    used_person_uid = models.CharField(max_length=20, blank=True, null=True)
+
 # FIXME make inheritance from TeckidsGroup work
 class TeckidsProject(ldapdb.models.Model, TeckidsLdapMixin):
     class Meta:
diff --git a/ticdesk_events/views.py b/ticdesk_events/views.py
index e84a563a4cf9ec5d823e0a9349f5425b3e09bcdd..e5a5500c0fd5894629f24aea8e8007a2e4517031 100644
--- a/ticdesk_events/views.py
+++ b/ticdesk_events/views.py
@@ -9,7 +9,7 @@ from django.shortcuts import redirect, render
 from django_tables2 import RequestConfig
 
 from .forms import EventFeedbackForm, EventRegisterForm
-from .models import TeckidsProject
+from .models import TeckidsProject, Voucher
 from .tables import EventsTable
 from .util import form_to_text_table, upload_file_to_media_url
 
@@ -55,7 +55,7 @@ def register_event(request, cn):
         'school_class': current_person.ou,
         'channel': 'none'
     }
-    register_form = EventRegisterForm(initial=initial)
+    register_form = EventRegisterForm(event, initial=initial)
 
     # Produce error if registration is not possible
     if not event.can_register:
@@ -68,7 +68,7 @@ def register_event(request, cn):
         return render(request, 'ticdesk_events/register_event.html', context)
 
     if request.method == 'POST':
-        register_form = EventRegisterForm(request.POST, initial=initial)
+        register_form = EventRegisterForm(event, request.POST, initial=initial)
         if register_form.is_valid():
             # Add the current person to the event
             event.add_member(current_person)
@@ -86,6 +86,17 @@ def register_event(request, cn):
                 current_person.mobile = register_form.cleaned_data['mobile']
                 current_person.save()
 
+            # Check discount voucher
+            if register_form.cleaned_data['voucher_code']:
+                voucher = Voucher.objects.get(code=register_form.cleaned_data['voucher_code'],
+                    project_cn=cn, used=False
+                )
+                voucher.used = True
+                voucher.used_person_uid = current_person.uid
+                voucher.save()
+            else:
+                voucher = None
+
             # Produce e-mail to registration queue
             message = EmailMessage()
             message.reply_to = (current_person.mail, register_form.cleaned_data['guardian_mail'])
@@ -102,6 +113,9 @@ def register_event(request, cn):
             ):
                 message.body += '***** ' + _('Geänderte Anschrift') + ' *****\n\n'
             message.body += form_to_text_table(register_form, 78)
+            if voucher:
+                message.body += '\n\n***** ' + _('Gutschein verwendet') + ' *****\n\n'
+                message.body += 'Rabatt: %d %%\n' % voucher.discount
 
             # Attach raw form data as attachment
             message.attach('register_form.json', json.dumps(register_form.cleaned_data, indent=4, default=str), 'application/json')