# -*- coding: utf-8 -*- from __future__ import unicode_literals import datetime import logging from django.core.exceptions import ValidationError from django.db import models from django.urls import reverse from django.utils import timezone from django.utils.translation import gettext_lazy as _ from dav_base.validators import DAVNumberValidator from dav_events.models.event import Event from . import signals logger = logging.getLogger(__name__) midnight = datetime.time(00, 00, 00) class Registration(models.Model): event = models.ForeignKey(Event, related_name='registrations', on_delete=models.PROTECT) created_at = models.DateTimeField(auto_now_add=True) personal_names = models.CharField(max_length=1024, verbose_name=_('Vorname(n)')) family_names = models.CharField(max_length=1024, verbose_name=_('Familienname')) address = models.CharField(max_length=1024, verbose_name=_('Anschrift'), help_text=_('Straße, Hausnummer')) postal_code = models.CharField(max_length=254, verbose_name=_('Postleitzahl')) city = models.CharField(max_length=1024, verbose_name=_('Ort')) email_address = models.EmailField(verbose_name=_('E-Mail-Adresse')) phone_number = models.CharField(max_length=254, verbose_name=_('Telefonnummer'), help_text=_('Idealerweise eine Mobilfunk-Nummer')) year_of_birth = models.IntegerField(verbose_name=_('Geburtsjahr'), help_text=_('Manchmal müssen wir wissen, wie alt unsere Teilnehmer sind.' ' Darum brauchen wir die vierstellige Jahreszahl,' ' des Jahres in dem du geboren bist (zb. 1991).')) apply_reduced_fee = models.BooleanField(default=False, verbose_name=_('Antrag auf reduzierte Teilnahmegebühr'), help_text=_('Für Jugendliche und Junioren' ' (bis zum vollendeten 25. Lebensjahr),' ' sowie Mitglieder mit geringen finanziellen Mitteln' ' (Nachweis durch "Karlsruher Pass"),' ' wird die Teilnahmegebühr auf 50% ermäßigt.')) dav_member = models.BooleanField(default=True, verbose_name=_('DAV Mitglied')) dav_number = models.CharField(max_length=62, blank=True, validators=[DAVNumberValidator], verbose_name=_('DAV Mitgliedsnummer'), help_text='%s
%s %s' % ( _('Deine Mitgliedsnummer findest du unter dem Strichcode' ' auf deinem DAV Ausweis.'), _('Beispiel: 131/00/012345'), _('(der Teil bis zum ersten * genügt)'), )) emergency_contact = models.TextField(blank=True, verbose_name=_('Notfall-Kontakt'), help_text=_('Name und Telefonnummer bzw. Anschrift,' ' die in Notfällen informiert werden soll.')) experience = models.TextField(blank=True, verbose_name=_('Erfahrung'), help_text=_('Welche Touren oder Kurse hast du bereits gemacht?')) note = models.TextField(blank=True, verbose_name=_('Anmerkung'), help_text='%s
%s' % ( _('Wissenswertes für den Tourenleiter, z.B. Allergien,' ' gesundheitliche Einschränkungen, ...'), _('Kann frei gelassen werden.')) ) privacy_policy = models.TextField(blank=True, verbose_name=_('Erklärung zur Datenspeicherung')) privacy_policy_accepted = models.BooleanField(default=False, verbose_name=_('Einwilligung zur Datenspeicherung')) purge_at = models.DateTimeField(_('Zeitpunkt der Datenlöschung')) answered_obsolete = models.BooleanField(default=False, verbose_name=_('Durch Tourleitung beantwortet')) def approx_age(self): now = datetime.datetime.now() year_now = now.year return year_now - self.year_of_birth @staticmethod def pk2hexstr(pk): return hex(pk * 113)[2:] # 113 has no meaning, but it produce nice looking hex codes. @staticmethod def hexstr2pk(hexstr): return int('0x' + hexstr, 0) // 113 @property def hexstr(self): if not self.pk: return None return self.pk2hexstr(self.pk) class Meta: verbose_name = _('Anmeldung') verbose_name_plural = _('Anmeldungen') ordering = ['created_at'] def __str__(self): return '{eventnumber} - {name} ({registration_id} - {created} - {purge})'.format( eventnumber=self.event.get_number(), name=self.get_full_name(), registration_id=self.hexstr, created=self.created_at.strftime('%d.%m.%Y %H:%M %Z'), purge=self.purge_at.strftime('%d.%m.%Y %H:%M %Z') ) def get_absolute_url(self): return reverse('dav_registration:registered') def get_full_name(self): return '{} {}'.format(self.personal_names, self.family_names) def get_info(self): text = """{fullname} {address}, {postal_code} {city} DAV Mitglied: {dav_info} Jahrgang: {year_of_birth} (ungefähres Alter: {approx_age}) Antrag auf reduzierte Teilnehmergebühr: {apply_reduced_fee_yesno} Erfahrung: {experience} Anmerkung: {note} """ if not self.dav_member: dav_info = _('Nein') else: dav_info = self.dav_number if self.apply_reduced_fee: apply_reduced_fee_yesno = _('Ja') else: apply_reduced_fee_yesno = _('Nein') return text.format( fullname=self.get_full_name(), address=self.address, postal_code=self.postal_code, city=self.city, dav_info=dav_info, year_of_birth=self.year_of_birth, approx_age=self.approx_age(), apply_reduced_fee_yesno=apply_reduced_fee_yesno, experience=self.experience, note=self.note, ) def get_data_dict(self): data = {} for field in self._meta.fields: if not field.primary_key: data[field.name] = getattr(self, field.name) return data def clean(self): if self.dav_member and not self.dav_number: raise ValidationError({'dav_number': _('Wenn du DAV Mitglied bist, brauchen wir deine Mitgliedsnummer.')}) def save(self, **kwargs): creating = False if not self.id: creating = True if not self.purge_at and self.event: self.purge_at = self.__class__.calc_purge_at(self.event) self.full_clean() super().save(**kwargs) if creating: status = RegistrationStatus(registration=self) status.save() logger.info('Registration stored: %s', self) signals.registration_created.send(sender=self.__class__, registration=self) @classmethod def calc_purge_at(cls, event): if event.alt_last_day: last_day = event.alt_last_day elif event.last_day: last_day = event.last_day elif event.alt_first_day: last_day = event.alt_first_day else: last_day = event.first_day april = datetime.date(last_day.year, 4, 1) july = datetime.date(last_day.year, 7, 1) july_nextyear = datetime.date(last_day.year + 1, 7, 1) october = datetime.date(last_day.year, 10, 1) january_nextyear = datetime.date(last_day.year + 1, 1, 1) if last_day < april: purge_date = july elif last_day < october: purge_date = january_nextyear else: purge_date = july_nextyear return timezone.make_aware(datetime.datetime.combine(purge_date, midnight)) class RegistrationStatus(models.Model): registration = models.OneToOneField(Registration, on_delete=models.CASCADE, related_name='status') updated_at = models.DateTimeField(auto_now=True) answered = models.BooleanField(_('Durch Tourleitung beantwortet'), default=False) accepted = models.BooleanField(_('Zusage erteilt'), null=True, blank=True) class Meta: verbose_name = _('Anmeldungsstatus') verbose_name_plural = _('Anmeldungsstati') ordering = ['updated_at'] def __str__(self): return '{} (Updated: {})'.format(self.registration, self.updated_at.strftime('%d.%m.%Y %H:%M:%S')) def clean(self): if self.accepted is not None and self.answered is not True: raise ValidationError({'answered': 'if accepted is not None, answered must be True'}) def save(self, **kwargs): self.full_clean() super().save(**kwargs) def set_accepted(self): self.accepted = True self.answered = True self.save() def set_rejected(self): self.accepted = False self.answered = True self.save() def reset(self): self.accepted = None self.answered = False self.save()