From 43d25c671fd877b4b9f6459e9c07c7a59d51573e Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Valentin=20Grou=C3=A8s?= <valentin.groues@uni.lu>
Date: Wed, 22 Mar 2017 22:44:50 +0100
Subject: [PATCH] split models into separate files

---
 smash/web/forms.py                      |   3 +-
 smash/web/models.py                     | 643 ------------------------
 smash/web/models/__init__.py            |  29 ++
 smash/web/models/appointment.py         | 112 +++++
 smash/web/models/appointment_type.py    |  64 +++
 smash/web/models/avaibility.py          |  32 ++
 smash/web/models/constants.py           |  16 +
 smash/web/models/flying_team.py         |  38 ++
 smash/web/models/holiday.py             |  25 +
 smash/web/models/item.py                |  29 ++
 smash/web/models/language.py            |  24 +
 smash/web/models/location.py            |  17 +
 smash/web/models/room.py                |  35 ++
 smash/web/models/subject.py             | 177 +++++++
 smash/web/models/visit.py               |  63 +++
 smash/web/models/worker.py              |  95 ++++
 smash/web/tests/functions.py            |   5 +-
 smash/web/tests/test_SubjectAddForm.py  |   6 +-
 smash/web/tests/test_SubjectEditForm.py |   5 +-
 19 files changed, 767 insertions(+), 651 deletions(-)
 delete mode 100644 smash/web/models.py
 create mode 100644 smash/web/models/__init__.py
 create mode 100644 smash/web/models/appointment.py
 create mode 100644 smash/web/models/appointment_type.py
 create mode 100644 smash/web/models/avaibility.py
 create mode 100644 smash/web/models/constants.py
 create mode 100644 smash/web/models/flying_team.py
 create mode 100644 smash/web/models/holiday.py
 create mode 100644 smash/web/models/item.py
 create mode 100644 smash/web/models/language.py
 create mode 100644 smash/web/models/location.py
 create mode 100644 smash/web/models/room.py
 create mode 100644 smash/web/models/subject.py
 create mode 100644 smash/web/models/visit.py
 create mode 100644 smash/web/models/worker.py

diff --git a/smash/web/forms.py b/smash/web/forms.py
index 35a319b8..5033f1a1 100644
--- a/smash/web/forms.py
+++ b/smash/web/forms.py
@@ -5,6 +5,7 @@ from django.forms import ModelForm, Form
 from django.utils.dates import MONTHS
 
 from models import Subject, Worker, Appointment, Visit, AppointmentType
+from models.constants import SUBJECT_TYPE_CHOICES
 
 """
 Possible redundancy, but if need arises, contents of forms can be easily customized
@@ -249,6 +250,6 @@ class StatisticsForm(Form):
         self.fields['month'] = forms.ChoiceField(choices=MONTHS.items(), initial=month)
         self.fields['year'] = forms.ChoiceField(choices=year_choices, initial=year)
         choices = [(-1, "all")]
-        choices.extend(Subject.SUBJECT_TYPE_CHOICES.items())
+        choices.extend(SUBJECT_TYPE_CHOICES.items())
         self.fields['subject_type'] = forms.ChoiceField(choices=choices, initial="-1")
         self.fields['visit'] = forms.ChoiceField(choices=visit_choices, initial="-1")
diff --git a/smash/web/models.py b/smash/web/models.py
deleted file mode 100644
index 4fd299bd..00000000
--- a/smash/web/models.py
+++ /dev/null
@@ -1,643 +0,0 @@
-from __future__ import unicode_literals
-
-import datetime
-
-from django.contrib.auth.models import User
-from django.db import models
-
-
-def get_current_year():
-    return datetime.datetime.now().year
-
-
-BOOL_CHOICES = ((True, 'Yes'), (False, 'No'))
-
-
-class Location(models.Model):
-    name = models.CharField(max_length=20)
-
-    def __str__(self):
-        return "%s" % self.name
-
-    def __unicode__(self):
-        return "%s" % self.name
-
-
-class Language(models.Model):
-    name = models.CharField(max_length=20)
-    image = models.ImageField()
-
-    def __str__(self):
-        return self.name
-
-    def image_img(self):
-        if self.image:
-            return u'<img class="flag-icon" src="%s" />' % (self.image.url)
-        else:
-            return 'No image'
-
-    image_img.short_description = 'Flag icon'
-    image_img.allow_tags = True
-
-
-class Subject(models.Model):
-    SEX_CHOICES_MALE = 'M'
-    SEX_CHOICES_FEMALE = 'F'
-
-    SEX_CHOICES = (
-        (SEX_CHOICES_MALE, 'Male'),
-        (SEX_CHOICES_FEMALE, 'Female'),
-    )
-
-    SUBJECT_TYPE_CHOICES_CONTROL = 'C'
-    SUBJECT_TYPE_CHOICES = {
-        SUBJECT_TYPE_CHOICES_CONTROL: 'CONTROL',
-        'P': 'PATIENT',
-    }
-
-    def finish_all_visits(self):
-        visits = Visit.objects.filter(subject=self, is_finished=False)
-        for visit in visits:
-            visit.is_finished = True
-            visit.save()
-
-    def finish_all_appointments(self):
-        appointments = Appointment.objects.filter(visit__subject=self, status=Appointment.APPOINTMENT_STATUS_SCHEDULED)
-        for appointment in appointments:
-            appointment.status = Appointment.APPOINTMENT_STATUS_CANCELLED
-            appointment.save()
-
-    def mark_as_dead(self):
-        self.dead = True
-        self.save()
-
-        self.finish_all_visits()
-        self.finish_all_appointments()
-
-    def mark_as_rejected(self):
-        self.resigned = True
-        self.save()
-
-        self.finish_all_visits()
-        self.finish_all_appointments()
-
-    sex = models.CharField(max_length=1,
-                           choices=SEX_CHOICES,
-                           verbose_name='Sex'
-                           )
-    postponed = models.BooleanField(choices=BOOL_CHOICES,
-                                    verbose_name='Postponed',
-                                    default=False
-                                    )
-    datetime_contact_reminder = models.DateField(
-        null=True,
-        blank=True,
-        verbose_name='Contact on',
-    )
-    type = models.CharField(max_length=1,
-                            choices=SUBJECT_TYPE_CHOICES.items(),
-                            verbose_name='Type'
-                            )
-
-    dead = models.BooleanField(
-        verbose_name='Dead',
-        default=False,
-        editable=False
-    )
-    resigned = models.BooleanField(
-        verbose_name='Resigned',
-        default=False,
-        editable=False
-    )
-    default_location = models.ForeignKey(Location,
-                                         verbose_name='Default appointment location',
-                                         )
-    first_name = models.CharField(max_length=50,
-                                  verbose_name='First name'
-                                  )
-    last_name = models.CharField(max_length=50,
-                                 verbose_name='Last name'
-                                 )
-    languages = models.ManyToManyField(Language,
-                                       blank=True,
-                                       verbose_name='Known languages'
-                                       )
-    default_written_communication_language = models.ForeignKey(Language,
-                                                               null=True,
-                                                               blank=True,
-                                                               related_name="%(class)s_written_comunication",
-                                                               verbose_name='Default language for document generation'
-                                                               )
-    phone_number = models.CharField(max_length=20,
-                                    null=True,
-                                    blank=True,
-                                    verbose_name='Phone number'
-                                    )
-    phone_number_2 = models.CharField(max_length=20,
-                                      null=True,
-                                      blank=True,
-                                      verbose_name='Phone number 2'
-                                      )
-    phone_number_3 = models.CharField(max_length=20,
-                                      null=True,
-                                      blank=True,
-                                      verbose_name='Phone number 3'
-                                      )
-    email = models.EmailField(
-        null=True,
-        blank=True,
-        verbose_name='E-mail'
-    )
-    date_born = models.DateField(
-        null=True,
-        blank=True,
-        verbose_name='Date of birth (YYYY-MM-DD)'
-    )
-    address = models.CharField(max_length=255,
-                               blank=True,
-                               verbose_name='Address'
-                               )
-    postal_code = models.CharField(max_length=7,
-                                   blank=True,
-                                   verbose_name='Postal code'
-                                   )
-    city = models.CharField(max_length=50,
-                            blank=True,
-                            verbose_name='City'
-                            )
-    country = models.CharField(max_length=50,
-                               verbose_name='Country'
-                               )
-    screening_number = models.CharField(max_length=50,
-                                        unique=True,
-                                        verbose_name='Screening number'
-                                        )
-    nd_number = models.CharField(max_length=6,
-                                 blank=True,
-                                 verbose_name='ND number'
-                                 )
-    mpower_id = models.CharField(max_length=20,
-                                 blank=True,
-                                 verbose_name='MPower ID'
-                                 )
-    comments = models.TextField(max_length=2000,
-                                blank=True,
-                                verbose_name='Comments'
-                                )
-    date_added = models.DateField(verbose_name='Added on',
-                                  auto_now=True
-                                  )
-    referral = models.CharField(max_length=128,
-                                null=True,
-                                blank=True,
-                                verbose_name='Referred by'
-                                )
-    diagnosis = models.CharField(max_length=128,
-                                 null=True,
-                                 blank=True,
-                                 verbose_name='Diagnosis'
-                                 )
-    year_of_diagnosis = models.IntegerField(
-        default=0,
-        null=True,
-        blank=True,
-        verbose_name='Year of diagnosis (YYYY)'
-    )
-
-    def latest_visit(self):
-        visits = self.visit_set.all()
-        if len(visits) == 0:
-            return None
-        result = visits[0]
-        for visit in visits:
-            if visit.datetime_begin > result.datetime_begin:
-                result = visit
-        return result
-
-    def __str__(self):
-        return "%s %s" % (self.first_name, self.last_name)
-
-    def __unicode__(self):
-        return "%s %s" % (self.first_name, self.last_name)
-
-
-class Item(models.Model):
-    is_fixed = models.BooleanField(
-        default=False,
-        verbose_name='Is the item fixed?'
-    )
-
-    disposable = models.BooleanField(
-        default=False,
-        verbose_name='Disposable set'
-    )
-
-    name = models.CharField(max_length=255,
-                            verbose_name='Name'
-                            )
-
-    def __str__(self):
-        return self.name
-
-    def __unicode__(self):
-        return self.name
-
-
-class Room(models.Model):
-    equipment = models.ManyToManyField(Item,
-                                       verbose_name='On-site equipment',
-                                       blank=True
-                                       )
-    owner = models.CharField(max_length=50,
-                             verbose_name='Owner'
-                             )
-    address = models.CharField(max_length=255,
-                               verbose_name='Address'
-                               )
-    city = models.CharField(max_length=50,
-                            verbose_name='City'
-                            )
-    room_number = models.IntegerField(
-        verbose_name='Room number'
-    )
-    floor = models.IntegerField(
-        verbose_name='Floor'
-    )
-    is_vehicle = models.BooleanField(
-        verbose_name='Is a vehicle?'
-    )
-
-    def __str__(self):
-        return "%d %s %s" % (self.room_number, self.address, self.city)
-
-    def __unicode__(self):
-        return "%d %s %s" % (self.room_number, self.address, self.city)
-
-
-class AppointmentType(models.Model):
-    DEFAULT_COLOR = '#cfc600'
-    DEFAULT_FONT_COLOR = '#00000'
-
-    required_equipment = models.ManyToManyField(Item,
-                                                verbose_name='Required equipment',
-                                                blank=True
-                                                )
-    code = models.CharField(max_length=20,
-                            verbose_name='Appointment code'
-                            )
-    description = models.CharField(max_length=2000,
-                                   verbose_name='Appointment description'
-                                   )
-    default_duration = models.IntegerField(
-        verbose_name='Default duration (in minutes)'
-    )
-    calendar_color_priority = models.IntegerField(
-        verbose_name='Calendar color priority',
-        default=1
-    )
-    calendar_color = models.CharField(max_length=2000,
-                                      verbose_name='Calendar color',
-                                      default=DEFAULT_COLOR
-                                      )
-    calendar_font_color = models.CharField(max_length=2000,
-                                           verbose_name='Calendar color',
-                                           default=DEFAULT_FONT_COLOR
-                                           )
-    rest_time = models.IntegerField(
-        verbose_name='Suggested rest time',
-        default=0
-    )
-    can_be_parallelized = models.BooleanField(
-        verbose_name='Can be parallelized',
-        default=False
-    )
-    REQ_ROLE_CHOICES = (
-        ('DOCTOR', 'Doctor'),
-        ('NURSE', 'Nurse'),
-        ('PSYCHOLOGIST', 'Psychologist'),
-        ('ANY', 'Any')
-    )
-    required_worker = models.CharField(max_length=20, choices=REQ_ROLE_CHOICES,
-                                       verbose_name='Type of worker required for appointment',
-                                       default='ANY'
-                                       )
-
-    class Meta:
-        ordering = ['description']
-
-    def __str__(self):
-        return self.description
-
-    def __unicode__(self):
-        return self.description
-
-
-class Worker(models.Model):
-    languages = models.ManyToManyField(Language,
-                                       verbose_name='Known languages'
-                                       )
-    locations = models.ManyToManyField(Location,
-                                       verbose_name='Locations'
-                                       )
-    appointments = models.ManyToManyField('Appointment', blank=True,
-                                          verbose_name='Appointments'
-                                          )
-    user = models.OneToOneField(User, blank=True, null=True,
-                                verbose_name='Username'
-                                )
-    first_name = models.CharField(max_length=50,
-                                  verbose_name='First name'
-                                  )
-    last_name = models.CharField(max_length=50,
-                                 verbose_name='Last name'
-                                 )
-    phone_number = models.CharField(max_length=20,
-                                    verbose_name='Phone number'
-                                    )
-    unit = models.CharField(max_length=50,
-                            verbose_name='Unit'
-                            )
-    email = models.EmailField(
-        verbose_name='E-mail'
-    )
-    ROLE_CHOICES_SECRETARY = "SECRETARY"
-    ROLE_CHOICES = (
-        ('DOCTOR', 'Doctor'),
-        ('NURSE', 'Nurse'),
-        ('PSYCHOLOGIST', 'Psychologist'),
-        ('TECHNICIAN', 'Technician'),
-        (ROLE_CHOICES_SECRETARY, 'Secretary')
-    )
-    role = models.CharField(max_length=20, choices=ROLE_CHOICES,
-                            verbose_name='Role'
-                            )
-    specialization = models.CharField(max_length=20,
-                                      verbose_name='Specialization'
-                                      )
-
-    def is_on_leave(self):
-        if len(self.holiday_set.filter(datetime_end__gt=datetime.datetime.now(),
-                                       datetime_start__lt=datetime.datetime.now())):
-            return True
-        return False
-
-    @staticmethod
-    def get_by_user(the_user):
-        if isinstance(the_user, User):
-            workers = Worker.objects.filter(user=the_user)
-            if len(workers) > 0:
-                return workers[0]
-            else:
-                return None
-        elif isinstance(the_user, Worker):
-            return the_user
-        elif the_user is not None:
-            raise TypeError("Unknown class type: " + the_user.__class__.__name__)
-        else:
-            return None
-
-    @staticmethod
-    def get_details(the_user):
-        if not the_user.is_authenticated:
-            return 'Guest', 'Test account'
-
-        person = Worker.objects.filter(user=the_user)
-
-        if len(person) == 0:
-            return the_user.get_full_name(), '<No worker information>'
-        else:
-            # For get_*_display, see:
-            # https://docs.djangoproject.com/en/1.10/topics/db/models/#field-options
-            return unicode(person[0]), person[0].get_role_display()
-
-    def __str__(self):
-        return "%s %s" % (self.first_name, self.last_name)
-
-    def __unicode__(self):
-        return "%s %s" % (self.first_name, self.last_name)
-
-
-class FlyingTeam(models.Model):
-    # doctor = models.ForeignKey(Worker, related_name='FlyingTeamDoctor',
-    #     verbose_name='Doctor'
-    # )
-    # nurse = models.ForeignKey(Worker, related_name='FlyingTeamNurse',
-    #     verbose_name='Nurse'
-    # )
-    # psychologist = models.ForeignKey(Worker, related_name='FlyingTeamPsychologist',
-    #     verbose_name='Psychologist'
-    # )
-    # datetime_called = models.DateTimeField(
-    #     verbose_name='Created on'
-    # )
-    # datetime_until = models.DateTimeField(
-    #     verbose_name='Disbanded on'
-    # )
-    #
-    # def __str__(self):
-    #     return "%s %s %s" % (self.doctor.last_name, self.nurse.last_name, self.psychologist.last_name)
-    #
-    # def __unicode__(self):
-    #     return "%s %s %s" % (self.doctor.last_name, self.nurse.last_name, self.psychologist.last_name)
-    place = models.CharField(max_length=255, verbose_name='Place')
-
-    def __str__(self):
-        return "%s" % self.place
-
-    def __unicode__(self):
-        return "%s" % self.place
-
-
-class Avaibility(models.Model):
-    person = models.ForeignKey(Worker, on_delete=models.CASCADE,
-                               verbose_name='Worker'
-                               )
-    day_number = models.IntegerField(
-        verbose_name='Day of the week'
-    )
-    available_from = models.TimeField(
-        verbose_name='Avaible since'
-    )
-    available_till = models.TimeField(
-        verbose_name='Avaible until'
-    )
-    is_current = models.BooleanField(
-        verbose_name='Is current?',
-        default=True
-    )
-
-    def __str__(self):
-        return "%d %s %s" % (self.day_number, self.person.last_name, self.person.first_name)
-
-    def __unicode__(self):
-        return "%d %s %s" % (self.day_number, self.person.last_name, self.person.first_name)
-
-
-class Holiday(models.Model):
-    person = models.ForeignKey(Worker, on_delete=models.CASCADE,
-                               verbose_name='Worker'
-                               )
-    datetime_start = models.DateTimeField(
-        verbose_name='On leave since'
-    )
-    datetime_end = models.DateTimeField(
-        verbose_name='On leave until'
-    )
-
-    def __str__(self):
-        return "%s %s" % (self.person.first_name, self.person.last_name)
-
-    def __unicode__(self):
-        return "%s %s" % (self.person.first_name, self.person.last_name)
-
-
-class Visit(models.Model):
-    subject = models.ForeignKey(Subject, on_delete=models.CASCADE,
-                                verbose_name='Subject'
-                                )
-    datetime_begin = models.DateTimeField(
-        verbose_name='Visit starts at'
-    )
-    datetime_end = models.DateTimeField(
-        verbose_name='Visit ends at'
-    )  # Deadline before which all appointments need to be scheduled
-
-    is_finished = models.BooleanField(
-        verbose_name='Has ended',
-        default=False
-    )
-    post_mail_sent = models.BooleanField(choices=BOOL_CHOICES,
-                                         verbose_name='Post mail sent',
-                                         default=False
-                                         )
-    appointment_types = models.ManyToManyField(AppointmentType,
-                                               verbose_name='Requested appointments',
-                                               blank=True,
-                                               )
-
-    def __unicode__(self):
-        return "%s %s" % (self.subject.first_name, self.subject.last_name)
-
-    def __str__(self):
-        return "%s %s" % (self.subject.first_name, self.subject.last_name)
-
-    def follow_up_title(self):
-        count = Visit.objects.filter(subject=self.subject, datetime_begin__lt=self.datetime_begin).count()
-        return "Visit " + str(count + 1)
-
-    def mark_as_finished(self):
-        self.is_finished = True
-        self.save()
-
-        if (not self.subject.dead) and (not self.subject.resigned):
-            visit_started = self.datetime_begin
-
-            time_to_next_visit = datetime.timedelta(days=365)
-            if self.subject.type == Subject.SUBJECT_TYPE_CHOICES_CONTROL:
-                time_to_next_visit = datetime.timedelta(days=365 * 3 + 366)
-
-            Visit.objects.create(
-                subject=self.subject,
-                datetime_begin=visit_started + time_to_next_visit,
-                datetime_end=visit_started + time_to_next_visit + datetime.timedelta(days=93)
-            )
-
-
-class Appointment(models.Model):
-    APPOINTMENT_STATUS_SCHEDULED = 'SCHEDULED'
-    APPOINTMENT_STATUS_FINISHED = 'FINISHED'
-    APPOINTMENT_STATUS_CANCELLED = 'CANCELLED'
-    APPOINTMENT_STATUS_NO_SHOW = 'NO_SHOW'
-    APPOINTMENT_STATUS_CHOICES = {
-        APPOINTMENT_STATUS_SCHEDULED: 'Scheduled',
-        APPOINTMENT_STATUS_FINISHED: 'Finished',
-        APPOINTMENT_STATUS_CANCELLED: 'Cancelled',
-        APPOINTMENT_STATUS_NO_SHOW: 'No Show',
-    }
-
-    flying_team = models.ForeignKey(FlyingTeam,
-                                    verbose_name='Flying team (if applicable)',
-                                    null=True, blank=True
-                                    )
-    worker_assigned = models.ForeignKey(Worker,
-                                        verbose_name='Worker conducting the assessment (if applicable)',
-                                        null=True, blank=True
-                                        )
-    appointment_types = models.ManyToManyField(AppointmentType,
-                                               verbose_name='Appointment types',
-                                               blank=True
-                                               )
-    room = models.ForeignKey(Room,
-                             verbose_name='Room ID',
-                             null=True,
-                             blank=True
-                             )
-    location = models.ForeignKey(Location,
-                                 verbose_name='Location',
-                                 )
-    visit = models.ForeignKey(Visit,
-                              verbose_name='Visit ID'
-                              )
-    comment = models.TextField(max_length=1024,
-                               verbose_name='Comment',
-                               null=True,
-                               blank=True
-                               )
-    datetime_when = models.DateTimeField(
-        verbose_name='Appointment on',
-        null=True, blank=True
-    )
-    length = models.IntegerField(
-        verbose_name='Appointment length (in minutes)'
-    )  # Potentially redundant; but can be used to manually adjust appointment's length
-
-    status = models.CharField(max_length=20, choices=APPOINTMENT_STATUS_CHOICES.items(),
-                              verbose_name='Status',
-                              editable=False,
-                              default=APPOINTMENT_STATUS_SCHEDULED
-                              )
-
-    def mark_as_finished(self):
-        self.status = Appointment.APPOINTMENT_STATUS_FINISHED
-        self.save()
-
-    def mark_as_cancelled(self):
-        self.status = Appointment.APPOINTMENT_STATUS_CANCELLED
-        self.save()
-
-    def mark_as_no_show(self):
-        self.status = Appointment.APPOINTMENT_STATUS_NO_SHOW
-        self.save()
-
-    def datetime_until(self):
-        if self.datetime_when is None:
-            return None
-        else:
-            return self.datetime_when + datetime.timedelta(minutes=max(self.length, 15))
-
-    def color(self):
-        result = AppointmentType.DEFAULT_COLOR
-        priority = 1000000
-        for type in self.appointment_types.all():
-            if type.calendar_color_priority < priority:
-                priority = type.calendar_color_priority
-                result = type.calendar_color
-        return result
-
-    def font_color(self):
-        result = AppointmentType.DEFAULT_FONT_COLOR
-        priority = 1000000
-        for type in self.appointment_types.all():
-            if type.calendar_color_priority < priority:
-                priority = type.calendar_color_priority
-                result = type.calendar_font_color
-        return result
-
-    def title(self):
-        if self.visit.subject.screening_number == "---":
-            return self.comment.replace("\n", ";").replace("\r", ";")
-        else:
-            title = self.visit.subject.first_name + " " + self.visit.subject.last_name + " type: "
-            for appointment_type in self.appointment_types.all():
-                title += appointment_type.code + ", "
-            return title
diff --git a/smash/web/models/__init__.py b/smash/web/models/__init__.py
new file mode 100644
index 00000000..553a5448
--- /dev/null
+++ b/smash/web/models/__init__.py
@@ -0,0 +1,29 @@
+# coding=utf-8
+from __future__ import unicode_literals
+
+import datetime
+
+from django.contrib.auth.models import User
+
+from flying_team import FlyingTeam
+from location import Location
+from room import Room
+from visit import Visit
+from worker import Worker
+from appointment import Appointment
+from appointment_type import AppointmentType
+from avaibility import Avaibility
+from holiday import Holiday
+from item import Item
+from language import Language
+from subject import Subject
+
+__author__ = 'Valentin Grouès'
+
+
+def get_current_year():
+    return datetime.datetime.now().year
+
+
+__all__ = [FlyingTeam, Appointment, AppointmentType, Avaibility, Holiday, Item, Language, Location, Room, Subject,
+           Visit, Worker]
diff --git a/smash/web/models/appointment.py b/smash/web/models/appointment.py
new file mode 100644
index 00000000..62e42d9a
--- /dev/null
+++ b/smash/web/models/appointment.py
@@ -0,0 +1,112 @@
+# coding=utf-8
+import datetime
+
+from django.db import models
+
+from constants import APPOINTMENT_TYPE_DEFAULT_COLOR, APPOINTMENT_TYPE_DEFAULT_FONT_COLOR
+from . import FlyingTeam, Location, Room, Visit, Worker
+
+__author__ = 'Valentin Grouès'
+
+
+class Appointment(models.Model):
+    class Meta:
+        app_label = 'web'
+
+    APPOINTMENT_STATUS_SCHEDULED = 'SCHEDULED'
+    APPOINTMENT_STATUS_FINISHED = 'FINISHED'
+    APPOINTMENT_STATUS_CANCELLED = 'CANCELLED'
+    APPOINTMENT_STATUS_NO_SHOW = 'NO_SHOW'
+    APPOINTMENT_STATUS_CHOICES = {
+        APPOINTMENT_STATUS_SCHEDULED: 'Scheduled',
+        APPOINTMENT_STATUS_FINISHED: 'Finished',
+        APPOINTMENT_STATUS_CANCELLED: 'Cancelled',
+        APPOINTMENT_STATUS_NO_SHOW: 'No Show',
+    }
+
+    flying_team = models.ForeignKey(FlyingTeam,
+                                    verbose_name='Flying team (if applicable)',
+                                    null=True, blank=True
+                                    )
+    worker_assigned = models.ForeignKey(Worker,
+                                        verbose_name='Worker conducting the assessment (if applicable)',
+                                        null=True, blank=True
+                                        )
+    appointment_types = models.ManyToManyField("web.AppointmentType",
+                                               verbose_name='Appointment types',
+                                               blank=True
+                                               )
+    room = models.ForeignKey(Room,
+                             verbose_name='Room ID',
+                             null=True,
+                             blank=True
+                             )
+    location = models.ForeignKey(Location,
+                                 verbose_name='Location',
+                                 )
+    visit = models.ForeignKey(Visit,
+                              verbose_name='Visit ID'
+                              )
+    comment = models.TextField(max_length=1024,
+                               verbose_name='Comment',
+                               null=True,
+                               blank=True
+                               )
+    datetime_when = models.DateTimeField(
+        verbose_name='Appointment on',
+        null=True, blank=True
+    )
+    length = models.IntegerField(
+        verbose_name='Appointment length (in minutes)'
+    )  # Potentially redundant; but can be used to manually adjust appointment's length
+
+    status = models.CharField(max_length=20, choices=APPOINTMENT_STATUS_CHOICES.items(),
+                              verbose_name='Status',
+                              editable=False,
+                              default=APPOINTMENT_STATUS_SCHEDULED
+                              )
+
+    def mark_as_finished(self):
+        self.status = Appointment.APPOINTMENT_STATUS_FINISHED
+        self.save()
+
+    def mark_as_cancelled(self):
+        self.status = Appointment.APPOINTMENT_STATUS_CANCELLED
+        self.save()
+
+    def mark_as_no_show(self):
+        self.status = Appointment.APPOINTMENT_STATUS_NO_SHOW
+        self.save()
+
+    def datetime_until(self):
+        if self.datetime_when is None:
+            return None
+        else:
+            return self.datetime_when + datetime.timedelta(minutes=max(self.length, 15))
+
+    def color(self):
+        result = APPOINTMENT_TYPE_DEFAULT_COLOR
+        priority = 1000000
+        for type in self.appointment_types.all():
+            if type.calendar_color_priority < priority:
+                priority = type.calendar_color_priority
+                result = type.calendar_color
+        return result
+
+    def font_color(self):
+        result = APPOINTMENT_TYPE_DEFAULT_FONT_COLOR
+        priority = 1000000
+        for type in self.appointment_types.all():
+            if type.calendar_color_priority < priority:
+                priority = type.calendar_color_priority
+                result = type.calendar_font_color
+        return result
+
+    def title(self):
+        if self.visit.subject.screening_number == "---":
+            return self.comment.replace("\n", ";").replace("\r", ";")
+        else:
+            title = self.visit.subject.first_name + " " + self.visit.subject.last_name + " type: "
+            for appointment_type in self.appointment_types.all():
+                title += appointment_type.code + ", "
+            return title
diff --git a/smash/web/models/appointment_type.py b/smash/web/models/appointment_type.py
new file mode 100644
index 00000000..9b3e48dc
--- /dev/null
+++ b/smash/web/models/appointment_type.py
@@ -0,0 +1,64 @@
+# coding=utf-8
+from django.db import models
+
+from constants import APPOINTMENT_TYPE_DEFAULT_COLOR, APPOINTMENT_TYPE_DEFAULT_FONT_COLOR
+
+__author__ = 'Valentin Grouès'
+
+
+class AppointmentType(models.Model):
+    class Meta:
+        app_label = 'web'
+
+    required_equipment = models.ManyToManyField("web.Item",
+                                                verbose_name='Required equipment',
+                                                blank=True
+                                                )
+    code = models.CharField(max_length=20,
+                            verbose_name='Appointment code'
+                            )
+    description = models.CharField(max_length=2000,
+                                   verbose_name='Appointment description'
+                                   )
+    default_duration = models.IntegerField(
+        verbose_name='Default duration (in minutes)'
+    )
+    calendar_color_priority = models.IntegerField(
+        verbose_name='Calendar color priority',
+        default=1
+    )
+    calendar_color = models.CharField(max_length=2000,
+                                      verbose_name='Calendar color',
+                                      default=APPOINTMENT_TYPE_DEFAULT_COLOR
+                                      )
+    calendar_font_color = models.CharField(max_length=2000,
+                                           verbose_name='Calendar color',
+                                           default=APPOINTMENT_TYPE_DEFAULT_FONT_COLOR
+                                           )
+    rest_time = models.IntegerField(
+        verbose_name='Suggested rest time',
+        default=0
+    )
+    can_be_parallelized = models.BooleanField(
+        verbose_name='Can be parallelized',
+        default=False
+    )
+    REQ_ROLE_CHOICES = (
+        ('DOCTOR', 'Doctor'),
+        ('NURSE', 'Nurse'),
+        ('PSYCHOLOGIST', 'Psychologist'),
+        ('ANY', 'Any')
+    )
+    required_worker = models.CharField(max_length=20, choices=REQ_ROLE_CHOICES,
+                                       verbose_name='Type of worker required for appointment',
+                                       default='ANY'
+                                       )
+
+    class Meta:
+        ordering = ['description']
+
+    def __str__(self):
+        return self.description
+
+    def __unicode__(self):
+        return self.description
diff --git a/smash/web/models/avaibility.py b/smash/web/models/avaibility.py
new file mode 100644
index 00000000..bbc465ad
--- /dev/null
+++ b/smash/web/models/avaibility.py
@@ -0,0 +1,32 @@
+# coding=utf-8
+from django.db import models
+
+__author__ = 'Valentin Grouès'
+
+
+class Avaibility(models.Model):
+    class Meta:
+        app_label = 'web'
+
+    person = models.ForeignKey("web.Worker", on_delete=models.CASCADE,
+                               verbose_name='Worker'
+                               )
+    day_number = models.IntegerField(
+        verbose_name='Day of the week'
+    )
+    available_from = models.TimeField(
+        verbose_name='Avaible since'
+    )
+    available_till = models.TimeField(
+        verbose_name='Avaible until'
+    )
+    is_current = models.BooleanField(
+        verbose_name='Is current?',
+        default=True
+    )
+
+    def __str__(self):
+        return "%d %s %s" % (self.day_number, self.person.last_name, self.person.first_name)
+
+    def __unicode__(self):
+        return "%d %s %s" % (self.day_number, self.person.last_name, self.person.first_name)
diff --git a/smash/web/models/constants.py b/smash/web/models/constants.py
new file mode 100644
index 00000000..1d8ad089
--- /dev/null
+++ b/smash/web/models/constants.py
@@ -0,0 +1,16 @@
+# coding=utf-8
+__author__ = 'Valentin Grouès'
+BOOL_CHOICES = ((True, 'Yes'), (False, 'No'))
+SEX_CHOICES_MALE = 'M'
+SEX_CHOICES_FEMALE = 'F'
+SEX_CHOICES = (
+    (SEX_CHOICES_MALE, 'Male'),
+    (SEX_CHOICES_FEMALE, 'Female'),
+)
+SUBJECT_TYPE_CHOICES_CONTROL = 'C'
+SUBJECT_TYPE_CHOICES = {
+    SUBJECT_TYPE_CHOICES_CONTROL: 'CONTROL',
+    'P': 'PATIENT',
+}
+APPOINTMENT_TYPE_DEFAULT_COLOR = '#cfc600'
+APPOINTMENT_TYPE_DEFAULT_FONT_COLOR = '#00000'
diff --git a/smash/web/models/flying_team.py b/smash/web/models/flying_team.py
new file mode 100644
index 00000000..04d6f670
--- /dev/null
+++ b/smash/web/models/flying_team.py
@@ -0,0 +1,38 @@
+# coding=utf-8
+from django.db import models
+
+__author__ = 'Valentin Grouès'
+
+
+class FlyingTeam(models.Model):
+    class Meta:
+        app_label = 'web'
+
+    # doctor = models.ForeignKey(Worker, related_name='FlyingTeamDoctor',
+    #     verbose_name='Doctor'
+    # )
+    # nurse = models.ForeignKey(Worker, related_name='FlyingTeamNurse',
+    #     verbose_name='Nurse'
+    # )
+    # psychologist = models.ForeignKey(Worker, related_name='FlyingTeamPsychologist',
+    #     verbose_name='Psychologist'
+    # )
+    # datetime_called = models.DateTimeField(
+    #     verbose_name='Created on'
+    # )
+    # datetime_until = models.DateTimeField(
+    #     verbose_name='Disbanded on'
+    # )
+    #
+    # def __str__(self):
+    #     return "%s %s %s" % (self.doctor.last_name, self.nurse.last_name, self.psychologist.last_name)
+    #
+    # def __unicode__(self):
+    #     return "%s %s %s" % (self.doctor.last_name, self.nurse.last_name, self.psychologist.last_name)
+    place = models.CharField(max_length=255, verbose_name='Place')
+
+    def __str__(self):
+        return "%s" % self.place
+
+    def __unicode__(self):
+        return "%s" % self.place
diff --git a/smash/web/models/holiday.py b/smash/web/models/holiday.py
new file mode 100644
index 00000000..6e3f37b4
--- /dev/null
+++ b/smash/web/models/holiday.py
@@ -0,0 +1,25 @@
+# coding=utf-8
+from django.db import models
+
+__author__ = 'Valentin Grouès'
+
+
+class Holiday(models.Model):
+    class Meta:
+        app_label = 'web'
+
+    person = models.ForeignKey("web.Worker", on_delete=models.CASCADE,
+                               verbose_name='Worker'
+                               )
+    datetime_start = models.DateTimeField(
+        verbose_name='On leave since'
+    )
+    datetime_end = models.DateTimeField(
+        verbose_name='On leave until'
+    )
+
+    def __str__(self):
+        return "%s %s" % (self.person.first_name, self.person.last_name)
+
+    def __unicode__(self):
+        return "%s %s" % (self.person.first_name, self.person.last_name)
diff --git a/smash/web/models/item.py b/smash/web/models/item.py
new file mode 100644
index 00000000..89467831
--- /dev/null
+++ b/smash/web/models/item.py
@@ -0,0 +1,29 @@
+# coding=utf-8
+from django.db import models
+
+__author__ = 'Valentin Grouès'
+
+
+class Item(models.Model):
+    class Meta:
+        app_label = 'web'
+
+    is_fixed = models.BooleanField(
+        default=False,
+        verbose_name='Is the item fixed?'
+    )
+
+    disposable = models.BooleanField(
+        default=False,
+        verbose_name='Disposable set'
+    )
+
+    name = models.CharField(max_length=255,
+                            verbose_name='Name'
+                            )
+
+    def __str__(self):
+        return self.name
+
+    def __unicode__(self):
+        return self.name
diff --git a/smash/web/models/language.py b/smash/web/models/language.py
new file mode 100644
index 00000000..58219183
--- /dev/null
+++ b/smash/web/models/language.py
@@ -0,0 +1,24 @@
+# coding=utf-8
+from django.db import models
+
+__author__ = 'Valentin Grouès'
+
+
+class Language(models.Model):
+    class Meta:
+        app_label = 'web'
+
+    name = models.CharField(max_length=20)
+    image = models.ImageField()
+
+    def __str__(self):
+        return self.name
+
+    def image_img(self):
+        if self.image:
+            return u'<img class="flag-icon" src="%s" />' % self.image.url
+        else:
+            return 'No image'
+
+    image_img.short_description = 'Flag icon'
+    image_img.allow_tags = True
diff --git a/smash/web/models/location.py b/smash/web/models/location.py
new file mode 100644
index 00000000..a81f2af3
--- /dev/null
+++ b/smash/web/models/location.py
@@ -0,0 +1,17 @@
+# coding=utf-8
+from django.db import models
+
+__author__ = 'Valentin Grouès'
+
+
+class Location(models.Model):
+    class Meta:
+        app_label = 'web'
+
+    name = models.CharField(max_length=20)
+
+    def __str__(self):
+        return "%s" % self.name
+
+    def __unicode__(self):
+        return "%s" % self.name
diff --git a/smash/web/models/room.py b/smash/web/models/room.py
new file mode 100644
index 00000000..1a02850b
--- /dev/null
+++ b/smash/web/models/room.py
@@ -0,0 +1,35 @@
+# coding=utf-8
+from django.db import models
+
+__author__ = 'Valentin Grouès'
+
+
+class Room(models.Model):
+    equipment = models.ManyToManyField("web.Item",
+                                       verbose_name='On-site equipment',
+                                       blank=True
+                                       )
+    owner = models.CharField(max_length=50,
+                             verbose_name='Owner'
+                             )
+    address = models.CharField(max_length=255,
+                               verbose_name='Address'
+                               )
+    city = models.CharField(max_length=50,
+                            verbose_name='City'
+                            )
+    room_number = models.IntegerField(
+        verbose_name='Room number'
+    )
+    floor = models.IntegerField(
+        verbose_name='Floor'
+    )
+    is_vehicle = models.BooleanField(
+        verbose_name='Is a vehicle?'
+    )
+
+    def __str__(self):
+        return "%d %s %s" % (self.room_number, self.address, self.city)
+
+    def __unicode__(self):
+        return "%d %s %s" % (self.room_number, self.address, self.city)
diff --git a/smash/web/models/subject.py b/smash/web/models/subject.py
new file mode 100644
index 00000000..2eddd765
--- /dev/null
+++ b/smash/web/models/subject.py
@@ -0,0 +1,177 @@
+# coding=utf-8
+from django.db import models
+
+from constants import BOOL_CHOICES, SEX_CHOICES, SUBJECT_TYPE_CHOICES
+from . import Appointment, Language, Location, Visit
+
+__author__ = 'Valentin Grouès'
+
+
+class Subject(models.Model):
+    class Meta:
+        app_label = 'web'
+
+    def finish_all_visits(self):
+        visits = Visit.objects.filter(subject=self, is_finished=False)
+        for visit in visits:
+            visit.is_finished = True
+            visit.save()
+
+    def finish_all_appointments(self):
+        appointments = Appointment.objects.filter(visit__subject=self, status=Appointment.APPOINTMENT_STATUS_SCHEDULED)
+        for appointment in appointments:
+            appointment.status = Appointment.APPOINTMENT_STATUS_CANCELLED
+            appointment.save()
+
+    def mark_as_dead(self):
+        self.dead = True
+        self.save()
+
+        self.finish_all_visits()
+        self.finish_all_appointments()
+
+    def mark_as_rejected(self):
+        self.resigned = True
+        self.save()
+
+        self.finish_all_visits()
+        self.finish_all_appointments()
+
+    sex = models.CharField(max_length=1,
+                           choices=SEX_CHOICES,
+                           verbose_name='Sex'
+                           )
+    postponed = models.BooleanField(choices=BOOL_CHOICES,
+                                    verbose_name='Postponed',
+                                    default=False
+                                    )
+    datetime_contact_reminder = models.DateField(
+        null=True,
+        blank=True,
+        verbose_name='Contact on',
+    )
+    type = models.CharField(max_length=1,
+                            choices=SUBJECT_TYPE_CHOICES.items(),
+                            verbose_name='Type'
+                            )
+
+    dead = models.BooleanField(
+        verbose_name='Dead',
+        default=False,
+        editable=False
+    )
+    resigned = models.BooleanField(
+        verbose_name='Resigned',
+        default=False,
+        editable=False
+    )
+    default_location = models.ForeignKey(Location,
+                                         verbose_name='Default appointment location',
+                                         )
+    first_name = models.CharField(max_length=50,
+                                  verbose_name='First name'
+                                  )
+    last_name = models.CharField(max_length=50,
+                                 verbose_name='Last name'
+                                 )
+    languages = models.ManyToManyField(Language,
+                                       blank=True,
+                                       verbose_name='Known languages'
+                                       )
+    default_written_communication_language = models.ForeignKey(Language,
+                                                               null=True,
+                                                               blank=True,
+                                                               related_name="%(class)s_written_comunication",
+                                                               verbose_name='Default language for document generation'
+                                                               )
+    phone_number = models.CharField(max_length=20,
+                                    null=True,
+                                    blank=True,
+                                    verbose_name='Phone number'
+                                    )
+    phone_number_2 = models.CharField(max_length=20,
+                                      null=True,
+                                      blank=True,
+                                      verbose_name='Phone number 2'
+                                      )
+    phone_number_3 = models.CharField(max_length=20,
+                                      null=True,
+                                      blank=True,
+                                      verbose_name='Phone number 3'
+                                      )
+    email = models.EmailField(
+        null=True,
+        blank=True,
+        verbose_name='E-mail'
+    )
+    date_born = models.DateField(
+        null=True,
+        blank=True,
+        verbose_name='Date of birth (YYYY-MM-DD)'
+    )
+    address = models.CharField(max_length=255,
+                               blank=True,
+                               verbose_name='Address'
+                               )
+    postal_code = models.CharField(max_length=7,
+                                   blank=True,
+                                   verbose_name='Postal code'
+                                   )
+    city = models.CharField(max_length=50,
+                            blank=True,
+                            verbose_name='City'
+                            )
+    country = models.CharField(max_length=50,
+                               verbose_name='Country'
+                               )
+    screening_number = models.CharField(max_length=50,
+                                        unique=True,
+                                        verbose_name='Screening number'
+                                        )
+    nd_number = models.CharField(max_length=6,
+                                 blank=True,
+                                 verbose_name='ND number'
+                                 )
+    mpower_id = models.CharField(max_length=20,
+                                 blank=True,
+                                 verbose_name='MPower ID'
+                                 )
+    comments = models.TextField(max_length=2000,
+                                blank=True,
+                                verbose_name='Comments'
+                                )
+    date_added = models.DateField(verbose_name='Added on',
+                                  auto_now=True
+                                  )
+    referral = models.CharField(max_length=128,
+                                null=True,
+                                blank=True,
+                                verbose_name='Referred by'
+                                )
+    diagnosis = models.CharField(max_length=128,
+                                 null=True,
+                                 blank=True,
+                                 verbose_name='Diagnosis'
+                                 )
+    year_of_diagnosis = models.IntegerField(
+        default=0,
+        null=True,
+        blank=True,
+        verbose_name='Year of diagnosis (YYYY)'
+    )
+
+    def latest_visit(self):
+        visits = self.visit_set.all()
+        if len(visits) == 0:
+            return None
+        result = visits[0]
+        for visit in visits:
+            if visit.datetime_begin > result.datetime_begin:
+                result = visit
+        return result
+
+    def __str__(self):
+        return "%s %s" % (self.first_name, self.last_name)
+
+    def __unicode__(self):
+        return "%s %s" % (self.first_name, self.last_name)
diff --git a/smash/web/models/visit.py b/smash/web/models/visit.py
new file mode 100644
index 00000000..313b960d
--- /dev/null
+++ b/smash/web/models/visit.py
@@ -0,0 +1,63 @@
+# coding=utf-8
+import datetime
+
+from django.db import models
+
+from constants import BOOL_CHOICES, SUBJECT_TYPE_CHOICES_CONTROL
+
+__author__ = 'Valentin Grouès'
+
+
+class Visit(models.Model):
+    class Meta:
+        app_label = 'web'
+
+    subject = models.ForeignKey("web.Subject", on_delete=models.CASCADE,
+                                verbose_name='Subject'
+                                )
+    datetime_begin = models.DateTimeField(
+        verbose_name='Visit starts at'
+    )
+    datetime_end = models.DateTimeField(
+        verbose_name='Visit ends at'
+    )  # Deadline before which all appointments need to be scheduled
+
+    is_finished = models.BooleanField(
+        verbose_name='Has ended',
+        default=False
+    )
+    post_mail_sent = models.BooleanField(choices=BOOL_CHOICES,
+                                         verbose_name='Post mail sent',
+                                         default=False
+                                         )
+    appointment_types = models.ManyToManyField("web.AppointmentType",
+                                               verbose_name='Requested appointments',
+                                               blank=True,
+                                               )
+
+    def __unicode__(self):
+        return "%s %s" % (self.subject.first_name, self.subject.last_name)
+
+    def __str__(self):
+        return "%s %s" % (self.subject.first_name, self.subject.last_name)
+
+    def follow_up_title(self):
+        count = Visit.objects.filter(subject=self.subject, datetime_begin__lt=self.datetime_begin).count()
+        return "Visit " + str(count + 1)
+
+    def mark_as_finished(self):
+        self.is_finished = True
+        self.save()
+
+        if (not self.subject.dead) and (not self.subject.resigned):
+            visit_started = self.datetime_begin
+
+            time_to_next_visit = datetime.timedelta(days=365)
+            if self.subject.type == SUBJECT_TYPE_CHOICES_CONTROL:
+                time_to_next_visit = datetime.timedelta(days=365 * 3 + 366)
+
+            Visit.objects.create(
+                subject=self.subject,
+                datetime_begin=visit_started + time_to_next_visit,
+                datetime_end=visit_started + time_to_next_visit + datetime.timedelta(days=93)
+            )
diff --git a/smash/web/models/worker.py b/smash/web/models/worker.py
new file mode 100644
index 00000000..d6bf3c1e
--- /dev/null
+++ b/smash/web/models/worker.py
@@ -0,0 +1,95 @@
+# coding=utf-8
+import datetime
+
+from django.contrib.auth.models import User
+from django.db import models
+
+__author__ = 'Valentin Grouès'
+
+
+class Worker(models.Model):
+    class Meta:
+        app_label = 'web'
+
+    languages = models.ManyToManyField("web.Language",
+                                       verbose_name='Known languages'
+                                       )
+    locations = models.ManyToManyField("web.Location",
+                                       verbose_name='Locations'
+                                       )
+    appointments = models.ManyToManyField('web.Appointment', blank=True,
+                                          verbose_name='Appointments'
+                                          )
+    user = models.OneToOneField(User, blank=True, null=True,
+                                verbose_name='Username'
+                                )
+    first_name = models.CharField(max_length=50,
+                                  verbose_name='First name'
+                                  )
+    last_name = models.CharField(max_length=50,
+                                 verbose_name='Last name'
+                                 )
+    phone_number = models.CharField(max_length=20,
+                                    verbose_name='Phone number'
+                                    )
+    unit = models.CharField(max_length=50,
+                            verbose_name='Unit'
+                            )
+    email = models.EmailField(
+        verbose_name='E-mail'
+    )
+    ROLE_CHOICES_SECRETARY = "SECRETARY"
+    ROLE_CHOICES = (
+        ('DOCTOR', 'Doctor'),
+        ('NURSE', 'Nurse'),
+        ('PSYCHOLOGIST', 'Psychologist'),
+        ('TECHNICIAN', 'Technician'),
+        (ROLE_CHOICES_SECRETARY, 'Secretary')
+    )
+    role = models.CharField(max_length=20, choices=ROLE_CHOICES,
+                            verbose_name='Role'
+                            )
+    specialization = models.CharField(max_length=20,
+                                      verbose_name='Specialization'
+                                      )
+
+    def is_on_leave(self):
+        if len(self.holiday_set.filter(datetime_end__gt=datetime.datetime.now(),
+                                       datetime_start__lt=datetime.datetime.now())):
+            return True
+        return False
+
+    @staticmethod
+    def get_by_user(the_user):
+        if isinstance(the_user, User):
+            workers = Worker.objects.filter(user=the_user)
+            if len(workers) > 0:
+                return workers[0]
+            else:
+                return None
+        elif isinstance(the_user, Worker):
+            return the_user
+        elif the_user is not None:
+            raise TypeError("Unknown class type: " + the_user.__class__.__name__)
+        else:
+            return None
+
+    @staticmethod
+    def get_details(the_user):
+        if not the_user.is_authenticated:
+            return 'Guest', 'Test account'
+
+        person = Worker.objects.filter(user=the_user)
+
+        if len(person) == 0:
+            return the_user.get_full_name(), '<No worker information>'
+        else:
+            # For get_*_display, see:
+            # https://docs.djangoproject.com/en/1.10/topics/db/models/#field-options
+            return unicode(person[0]), person[0].get_role_display()
+
+    def __str__(self):
+        return "%s %s" % (self.first_name, self.last_name)
+
+    def __unicode__(self):
+        return "%s %s" % (self.first_name, self.last_name)
diff --git a/smash/web/tests/functions.py b/smash/web/tests/functions.py
index 3b5f1a3e..98c169a9 100644
--- a/smash/web/tests/functions.py
+++ b/smash/web/tests/functions.py
@@ -3,6 +3,7 @@ import datetime
 from django.contrib.auth.models import User
 
 from web.models import Location, AppointmentType, Subject, Worker, Visit, Appointment
+from web.models.constants import SEX_CHOICES_MALE, SUBJECT_TYPE_CHOICES_CONTROL
 from web.views import get_today_midnight_date
 
 
@@ -31,8 +32,8 @@ def create_subject():
         first_name="Piotr",
         last_name="Gawron",
         default_location=get_test_location(),
-        sex=Subject.SEX_CHOICES_MALE,
-        type=Subject.SUBJECT_TYPE_CHOICES_CONTROL,
+        sex=SEX_CHOICES_MALE,
+        type=SUBJECT_TYPE_CHOICES_CONTROL,
         screening_number="piotr's number",
         country="france")
 
diff --git a/smash/web/tests/test_SubjectAddForm.py b/smash/web/tests/test_SubjectAddForm.py
index c0af1e31..8cac955f 100644
--- a/smash/web/tests/test_SubjectAddForm.py
+++ b/smash/web/tests/test_SubjectAddForm.py
@@ -2,7 +2,7 @@ from django.test import TestCase
 
 from functions import get_test_location
 from web.forms import SubjectAddForm
-from web.models import Subject
+from web.models.constants import SEX_CHOICES_MALE, SUBJECT_TYPE_CHOICES_CONTROL
 
 
 class SubjectAddFormTests(TestCase):
@@ -10,8 +10,8 @@ class SubjectAddFormTests(TestCase):
         location = get_test_location()
         self.sample_data = {'first_name': 'name',
                             'last_name': 'name',
-                            'sex': Subject.SEX_CHOICES_MALE,
-                            'type': Subject.SUBJECT_TYPE_CHOICES_CONTROL,
+                            'sex': SEX_CHOICES_MALE,
+                            'type': SUBJECT_TYPE_CHOICES_CONTROL,
                             'default_location': location.id,
                             'screening_number': "123",
                             'country': 'Luxembourg'
diff --git a/smash/web/tests/test_SubjectEditForm.py b/smash/web/tests/test_SubjectEditForm.py
index 7baf1732..a5de02f9 100644
--- a/smash/web/tests/test_SubjectEditForm.py
+++ b/smash/web/tests/test_SubjectEditForm.py
@@ -4,6 +4,7 @@ from functions import get_test_location
 from web.forms import SubjectAddForm
 from web.forms import SubjectEditForm
 from web.models import Subject
+from web.models.constants import SEX_CHOICES_MALE, SUBJECT_TYPE_CHOICES_CONTROL
 
 
 class SubjectEditFormTests(TestCase):
@@ -11,8 +12,8 @@ class SubjectEditFormTests(TestCase):
         location = get_test_location()
         self.sample_data = {'first_name': 'name',
                             'last_name': 'name',
-                            'sex': Subject.SEX_CHOICES_MALE,
-                            'type': Subject.SUBJECT_TYPE_CHOICES_CONTROL,
+                            'sex': SEX_CHOICES_MALE,
+                            'type': SUBJECT_TYPE_CHOICES_CONTROL,
                             'default_location': location.id,
                             'country': 'Luxembourg',
                             'screening_number': '123',
-- 
GitLab