From 00e3f22cd666900d14170feb4b413f0853991b3c Mon Sep 17 00:00:00 2001
From: Piotr Gawron <piotr.gawron@uni.lu>
Date: Tue, 28 Nov 2017 16:17:24 +0100
Subject: [PATCH] address, city, country, data_born,
 default_written_communication_language, email, first_name, languages,
 last_name, phone_number, phone_number_2, phone_number_3, postal_code removed
 from study_subject (all this information is stored in subject)

the code is fixed so unit test passes
---
 smash/web/api_views/appointment.py            | 10 +--
 smash/web/api_views/subject.py                | 54 ++++++++-------
 smash/web/forms.py                            |  5 +-
 .../web/migrations/0070_auto_20171128_1124.py | 67 ++++++++++++++++++
 smash/web/models/mail_template.py             | 28 ++++----
 smash/web/models/study_subject.py             | 69 ++-----------------
 smash/web/models/visit.py                     |  4 +-
 smash/web/redcap_connector.py                 | 10 +--
 smash/web/templates/export/index.html         |  4 +-
 smash/web/templates/subjects/add.html         | 30 ++++++--
 smash/web/tests/api_views/test_appointment.py | 28 ++++----
 smash/web/tests/api_views/test_subject.py     | 45 +++++-------
 .../tests/forms/test_StudySubjectAddForm.py   | 19 ++---
 .../tests/forms/test_StudySubjectEditForm.py  | 59 +++++++---------
 smash/web/tests/functions.py                  |  3 -
 smash/web/tests/models/test_mail_template.py  |  8 ++-
 smash/web/tests/models/test_visit.py          |  3 +-
 smash/web/tests/test_RedcapConnector.py       | 24 +++----
 smash/web/tests/view/test_appointments.py     | 31 ++++-----
 smash/web/tests/view/test_visit.py            |  4 +-
 smash/web/views/appointment.py                | 27 +++++---
 smash/web/views/export.py                     | 24 ++++---
 smash/web/views/subject.py                    |  9 +--
 smash/web/views/visit.py                      | 10 +--
 24 files changed, 298 insertions(+), 277 deletions(-)
 create mode 100644 smash/web/migrations/0070_auto_20171128_1124.py

diff --git a/smash/web/api_views/appointment.py b/smash/web/api_views/appointment.py
index a51ddfc0..14a96d62 100644
--- a/smash/web/api_views/appointment.py
+++ b/smash/web/api_views/appointment.py
@@ -87,11 +87,11 @@ def serialize_appointment(appointment):
     nd_number = screening_number = phone_numbers = appointment_types = None
     if appointment.visit is not None:
         title = "Visit " + str(appointment.visit.visit_number)
-        subject = appointment.visit.subject
-        subject_string = subject.last_name + " " + subject.first_name
-        nd_number = subject.nd_number
-        screening_number = subject.screening_number
-        phone_numbers = ", ".join(filter(None, [subject.phone_number, subject.phone_number_2, subject.phone_number_3]))
+        study_subject = appointment.visit.subject
+        subject_string = study_subject.subject.last_name + " " + study_subject.subject.first_name
+        nd_number = study_subject.nd_number
+        screening_number = study_subject.screening_number
+        phone_numbers = ", ".join(filter(None, [study_subject.subject.phone_number, study_subject.subject.phone_number_2, study_subject.subject.phone_number_3]))
         appointment_types = ", ".join([unicode(type) for type in appointment.appointment_types.all()])
     else:
         title = appointment.comment
diff --git a/smash/web/api_views/subject.py b/smash/web/api_views/subject.py
index 3cff62ba..6c864c10 100644
--- a/smash/web/api_views/subject.py
+++ b/smash/web/api_views/subject.py
@@ -5,7 +5,7 @@ from django.db.models import Count, Case, When, Min
 from django.db.models import Q
 from django.http import JsonResponse
 
-from web.models import StudySubject, Visit, Appointment
+from web.models import Subject, StudySubject, Visit, Appointment
 from web.models.constants import SUBJECT_TYPE_CHOICES
 from web.views import e500_error
 from web.views.notifications import get_subjects_with_no_visit, get_subjects_with_reminder, get_today_midnight_date
@@ -16,10 +16,14 @@ logger = logging.getLogger(__name__)
 
 @login_required
 def cities(request):
-    result_subjects = StudySubject.objects.filter(city__isnull=False).values_list('city').distinct()
-    return JsonResponse({
-        "cities": [x[0] for x in result_subjects]
-    })
+    try:
+        result_subjects = Subject.objects.filter(city__isnull=False).values_list('city').distinct()
+        return JsonResponse({
+            "cities": [x[0] for x in result_subjects]
+        })
+    except Exception as e:
+        logger.error(e, exc_info=True)
+        return e500_error(request)
 
 
 @login_required
@@ -55,9 +59,9 @@ def get_subjects_order(subjects_to_be_ordered, order_column, order_direction):
     else:
         order_direction = "-"
     if order_column == "first_name":
-        result = subjects_to_be_ordered.order_by(order_direction + 'first_name')
+        result = subjects_to_be_ordered.order_by(order_direction + 'subject__first_name')
     elif order_column == "last_name":
-        result = subjects_to_be_ordered.order_by(order_direction + 'last_name')
+        result = subjects_to_be_ordered.order_by(order_direction + 'subject__last_name')
     elif order_column == "nd_number":
         result = subjects_to_be_ordered.order_by(order_direction + 'nd_number')
     elif order_column == "screening_number":
@@ -77,7 +81,7 @@ def get_subjects_order(subjects_to_be_ordered, order_column, order_direction):
     elif order_column == "id":
         result = subjects_to_be_ordered.order_by(order_direction + 'id')
     elif order_column == "date_born":
-        result = subjects_to_be_ordered.order_by(order_direction + 'date_born')
+        result = subjects_to_be_ordered.order_by(order_direction + 'subject__date_born')
     elif order_column == "visit_1":
         result = order_by_visit(subjects_to_be_ordered, order_direction, 1)
     elif order_column == "visit_2":
@@ -166,9 +170,9 @@ def get_subjects_filtered(subjects_to_be_filtered, filters):
         column = row[0]
         value = row[1]
         if column == "first_name":
-            result = result.filter(first_name__icontains=value)
+            result = result.filter(subject__first_name__icontains=value)
         elif column == "last_name":
-            result = result.filter(last_name__icontains=value)
+            result = result.filter(subject__last_name__icontains=value)
         elif column == "nd_number":
             result = result.filter(nd_number__icontains=value)
         elif column == "screening_number":
@@ -283,11 +287,11 @@ def serialize_subject_visit(visit):
     pass
 
 
-def serialize_subject(subject):
+def serialize_subject(study_subject):
     location = ""
-    if subject.default_location is not None:
-        location = subject.default_location.name
-    visits = Visit.objects.filter(subject=subject).order_by('visit_number')
+    if study_subject.default_location is not None:
+        location = study_subject.default_location.name
+    visits = Visit.objects.filter(subject=study_subject).order_by('visit_number')
     serialized_visits = []
     for visit in visits:
         if visit.datetime_begin < get_today_midnight_date():
@@ -316,18 +320,18 @@ def serialize_subject(subject):
         })
 
     result = {
-        "first_name": subject.first_name,
-        "last_name": subject.last_name,
-        "date_born": subject.date_born,
-        "nd_number": subject.nd_number,
-        "screening_number": subject.screening_number,
+        "first_name": study_subject.subject.first_name,
+        "last_name": study_subject.subject.last_name,
+        "date_born": study_subject.subject.date_born,
+        "nd_number": study_subject.nd_number,
+        "screening_number": study_subject.screening_number,
         "default_location": location,
-        "dead": get_yes_no(subject.subject.dead),
-        "resigned": get_yes_no(subject.resigned),
-        "postponed": get_yes_no(subject.postponed),
-        "information_sent": get_yes_no(subject.information_sent),
-        "type": subject.get_type_display(),
-        "id": subject.id,
+        "dead": get_yes_no(study_subject.subject.dead),
+        "resigned": get_yes_no(study_subject.resigned),
+        "postponed": get_yes_no(study_subject.postponed),
+        "information_sent": get_yes_no(study_subject.information_sent),
+        "type": study_subject.get_type_display(),
+        "id": study_subject.id,
         "visits": serialized_visits,
     }
     return result
diff --git a/smash/web/forms.py b/smash/web/forms.py
index 2c2ed3d4..2402d689 100644
--- a/smash/web/forms.py
+++ b/smash/web/forms.py
@@ -110,7 +110,6 @@ class StudySubjectAddForm(ModelForm):
 
             if len(subjects_from_db) > 0:
                 self.add_error('screening_number', "Screening number already in use")
-        validate_subject_country(self, cleaned_data)
         validate_subject_nd_number(self, cleaned_data)
         validate_subject_mpower_number(self, cleaned_data)
         return cleaned_data
@@ -177,13 +176,11 @@ class StudySubjectEditForm(ModelForm):
     def clean(self):
         validate_subject_nd_number(self, self.cleaned_data)
         validate_subject_mpower_number(self, self.cleaned_data)
-        validate_subject_country(self, self.cleaned_data)
         validate_subject_resign_reason(self, self.cleaned_data)
 
     class Meta:
         model = StudySubject
         fields = '__all__'
-        exclude = ['subject']
 
 
 class WorkerAddForm(ModelForm):
@@ -343,7 +340,7 @@ class VisitDetailForm(ModelForm):
 
 
 class VisitAddForm(ModelForm):
-    subject = forms.ModelChoiceField(queryset=StudySubject.objects.order_by('last_name', 'first_name'))
+    subject = forms.ModelChoiceField(queryset=StudySubject.objects.order_by('subject__last_name', 'subject__first_name'))
     datetime_begin = forms.DateField(label="Visit begins on",
                                      widget=forms.TextInput(attrs=DATEPICKER_DATE_ATTRS)
                                      )
diff --git a/smash/web/migrations/0070_auto_20171128_1124.py b/smash/web/migrations/0070_auto_20171128_1124.py
new file mode 100644
index 00000000..fe02c8a9
--- /dev/null
+++ b/smash/web/migrations/0070_auto_20171128_1124.py
@@ -0,0 +1,67 @@
+# -*- coding: utf-8 -*-
+# Generated by Django 1.10.7 on 2017-11-28 11:24
+from __future__ import unicode_literals
+
+from django.db import migrations
+
+
+class Migration(migrations.Migration):
+
+    dependencies = [
+        ('web', '0069_remove_studysubject_sex'),
+    ]
+
+    operations = [
+        migrations.RemoveField(
+            model_name='studysubject',
+            name='address',
+        ),
+        migrations.RemoveField(
+            model_name='studysubject',
+            name='city',
+        ),
+        migrations.RemoveField(
+            model_name='studysubject',
+            name='country',
+        ),
+        migrations.RemoveField(
+            model_name='studysubject',
+            name='date_born',
+        ),
+        migrations.RemoveField(
+            model_name='studysubject',
+            name='default_written_communication_language',
+        ),
+        migrations.RemoveField(
+            model_name='studysubject',
+            name='email',
+        ),
+        migrations.RemoveField(
+            model_name='studysubject',
+            name='first_name',
+        ),
+        migrations.RemoveField(
+            model_name='studysubject',
+            name='languages',
+        ),
+        migrations.RemoveField(
+            model_name='studysubject',
+            name='last_name',
+        ),
+        migrations.RemoveField(
+            model_name='studysubject',
+            name='phone_number',
+        ),
+        migrations.RemoveField(
+            model_name='studysubject',
+            name='phone_number_2',
+        ),
+        migrations.RemoveField(
+            model_name='studysubject',
+            name='phone_number_3',
+        ),
+        migrations.RemoveField(
+            model_name='studysubject',
+            name='postal_code',
+        ),
+    ]
diff --git a/smash/web/models/mail_template.py b/smash/web/models/mail_template.py
index cdbc8f86..5d6e081b 100644
--- a/smash/web/models/mail_template.py
+++ b/smash/web/models/mail_template.py
@@ -196,31 +196,31 @@ class MailTemplate(models.Model):
 
     def _add_subject_replacements(self, replacements, study_subject):
         if study_subject is not None:
-            if study_subject.date_born is not None:
-                date_born = study_subject.date_born.strftime(DATE_FORMAT_SHORT)
+            if study_subject.subject.date_born is not None:
+                date_born = study_subject.subject.date_born.strftime(DATE_FORMAT_SHORT)
             else:
                 date_born = None
             replacements.update({
                 "##S_FULL_NAME##": unicode(study_subject),
-                "##S_FIRST_NAME##": study_subject.first_name,
-                "##S_LAST_NAME##": study_subject.last_name,
-                "##S_ADDRESS##": study_subject.address,
-                "##S_CITY##": study_subject.city,
-                "##S_COUNTRY##": unicode(study_subject.country),
+                "##S_FIRST_NAME##": study_subject.subject.first_name,
+                "##S_LAST_NAME##": study_subject.subject.last_name,
+                "##S_ADDRESS##": study_subject.subject.address,
+                "##S_CITY##": study_subject.subject.city,
+                "##S_COUNTRY##": unicode(study_subject.subject.country),
                 "##S_DIAGNOSIS_YEAR##": study_subject.year_of_diagnosis,
                 "##S_DATE_ADDED##": study_subject.date_added.strftime(DATE_FORMAT_SHORT),
                 "##S_DATE_BORN##": date_born,
                 "##S_DIAGNOSIS##": study_subject.diagnosis,
-                "##S_EMAIL##": study_subject.email,
+                "##S_EMAIL##": study_subject.subject.email,
                 "##S_SEX##": study_subject.subject.get_sex_display(),
                 "##S_MPOWER_ID##": study_subject.mpower_id,
                 "##S_ND_NUMBER##": study_subject.nd_number,
-                "##S_PHONE_NUMBER##": study_subject.phone_number,
-                "##S_PHONE_NUMBER_2##": study_subject.phone_number_2,
-                "##S_PHONE_NUMBER_3##": study_subject.phone_number_3,
-                "##S_POST_CODE##": study_subject.postal_code,
+                "##S_PHONE_NUMBER##": study_subject.subject.phone_number,
+                "##S_PHONE_NUMBER_2##": study_subject.subject.phone_number_2,
+                "##S_PHONE_NUMBER_3##": study_subject.subject.phone_number_3,
+                "##S_POST_CODE##": study_subject.subject.postal_code,
                 "##S_SCREENING_NUMBER##": study_subject.screening_number,
                 "##S_TYPE##": study_subject.get_type_display(),
-                '##S_MAIL_LANGUAGE##': str(study_subject.default_written_communication_language),
-                '##S_KNOWN_LANGUAGES##': ", ".join([l.name for l in study_subject.languages.all()])
+                '##S_MAIL_LANGUAGE##': str(study_subject.subject.default_written_communication_language),
+                '##S_KNOWN_LANGUAGES##': ", ".join([l.name for l in study_subject.subject.languages.all()])
             })
diff --git a/smash/web/models/study_subject.py b/smash/web/models/study_subject.py
index 77e31e0a..7fdc2eac 100644
--- a/smash/web/models/study_subject.py
+++ b/smash/web/models/study_subject.py
@@ -2,9 +2,8 @@
 from django.core.validators import RegexValidator
 from django.db import models
 
-from constants import BOOL_CHOICES, SEX_CHOICES, SUBJECT_TYPE_CHOICES, COUNTRY_OTHER_ID
-from web.models import Country
-from . import Appointment, Language, Location, Visit
+from constants import BOOL_CHOICES, SUBJECT_TYPE_CHOICES
+from . import Appointment, Location, Visit
 
 
 class StudySubject(models.Model):
@@ -30,6 +29,7 @@ class StudySubject(models.Model):
 
     subject = models.ForeignKey("web.Subject",
                                 verbose_name='Subject',
+                                editable=False,
                                 null=False,
                                 )
 
@@ -56,65 +56,6 @@ class StudySubject(models.Model):
                                     null=True, blank=True
                                     )
 
-    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.ForeignKey(Country,
-                                null=False,
-                                blank=False,
-                                default=COUNTRY_OTHER_ID,
-                                verbose_name='Country'
-                                )
     screening_number = models.CharField(max_length=50,
                                         unique=True,
                                         verbose_name='Screening number', blank=False, null=False
@@ -172,7 +113,7 @@ class StudySubject(models.Model):
                                      )
 
     def __str__(self):
-        return "%s %s" % (self.first_name, self.last_name)
+        return "%s %s" % (self.subject.first_name, self.subject.last_name)
 
     def __unicode__(self):
-        return "%s %s" % (self.first_name, self.last_name)
+        return "%s %s" % (self.subject.first_name, self.subject.last_name)
diff --git a/smash/web/models/visit.py b/smash/web/models/visit.py
index ab3252a4..61b29704 100644
--- a/smash/web/models/visit.py
+++ b/smash/web/models/visit.py
@@ -42,10 +42,10 @@ class Visit(models.Model):
     )
 
     def __unicode__(self):
-        return "%s %s" % (self.subject.first_name, self.subject.last_name)
+        return "%s %s" % (self.subject.subject.first_name, self.subject.subject.last_name)
 
     def __str__(self):
-        return "%s %s" % (self.subject.first_name, self.subject.last_name)
+        return "%s %s" % (self.subject.subject.first_name, self.subject.subject.last_name)
 
     def mark_as_finished(self):
         self.is_finished = True
diff --git a/smash/web/redcap_connector.py b/smash/web/redcap_connector.py
index 91995213..8a282858 100644
--- a/smash/web/redcap_connector.py
+++ b/smash/web/redcap_connector.py
@@ -179,8 +179,8 @@ class RedcapConnector(object):
             field = InconsistentField.create("sex", study_subject.subject.sex, red_cap_subject.sex)
             fields.append(field)
         subject_date_born = ""
-        if study_subject.date_born is not None:
-            subject_date_born = study_subject.date_born.strftime('%Y-%m-%d')
+        if study_subject.subject.date_born is not None:
+            subject_date_born = study_subject.subject.date_born.strftime('%Y-%m-%d')
         redcap_subject_date_born = red_cap_subject.date_born
         if redcap_subject_date_born is None:
             redcap_subject_date_born = ""
@@ -197,15 +197,15 @@ class RedcapConnector(object):
             fields.append(field)
         missing_language = False
         if len(red_cap_subject.languages) < 4:
-            for language in study_subject.languages.all():
+            for language in study_subject.subject.languages.all():
                 if language not in red_cap_subject.languages:
                     missing_language = True
         for language in red_cap_subject.languages:
-            if language not in study_subject.languages.all():
+            if language not in study_subject.subject.languages.all():
                 missing_language = True
         if missing_language:
             subject_languages = ""
-            for language in study_subject.languages.all():
+            for language in study_subject.subject.languages.all():
                 subject_languages += language.name + ", "
             red_cap_subject_languages = ""
             for language in red_cap_subject.languages:
diff --git a/smash/web/templates/export/index.html b/smash/web/templates/export/index.html
index a4e8aef2..39276ce9 100644
--- a/smash/web/templates/export/index.html
+++ b/smash/web/templates/export/index.html
@@ -24,12 +24,12 @@
             <li><a href="{% url 'web.views.export_to_excel' 'subjects' %}"><i class="fa fa-file-excel-o"></i> XLS -
                 Excel</a>
             </li>
-            <li><a href="{% url 'web.views.export_to_excel' 'appointments' %}"><i class="fa fa-file-text-o"></i> CSV -
+            <li><a href="{% url 'web.views.export_to_csv' 'subjects' %}"><i class="fa fa-file-text-o"></i> CSV -
                 Text based</a></li>
         </ul>
         <h3>Appointments</h3>
         <ul>
-            <li><a href="{% url 'web.views.export_to_csv' 'subjects' %}"><i class="fa fa-file-excel-o"></i> XLS -
+            <li><a href="{% url 'web.views.export_to_excel' 'appointments' %}"><i class="fa fa-file-excel-o"></i> XLS -
                 Excel</a></li>
             <li><a href="{% url 'web.views.export_to_csv' 'appointments' %}"><i class="fa fa-file-text-o"></i> CSV -
                 Text based</a></li>
diff --git a/smash/web/templates/subjects/add.html b/smash/web/templates/subjects/add.html
index 317c54e6..7be0c6dc 100644
--- a/smash/web/templates/subjects/add.html
+++ b/smash/web/templates/subjects/add.html
@@ -28,16 +28,36 @@
                 <a href="{% url 'web.views.subjects' %}" class="btn btn-block btn-default">Cancel</a>
             </div>
 
-            {% comment %} <div class="box-header with-border">
-		<h3 class="box-title">Details of subject</h3>
-	</div>{% endcomment %}
-
             <form method="post" action="" class="form-horizontal">
                 {% csrf_token %}
 
+
                 <div class="box-body">
                     <div class="col-sm-6">
-                        {% for field in form %}
+                        <div class="box-header">
+                            <h3>Subject data</h3>
+                        </div>
+                        {% for field in subject_form %}
+                            <div class="form-group {% if field.errors %}has-error{% endif %}">
+                                <label class="col-sm-4 control-label">
+                                    {{ field.label }}
+                                </label>
+
+                                <div class="col-sm-8">
+                                    {{ field|add_class:'form-control' }}
+                                </div>
+
+                                {% if field.errors %}
+                                    <span class="help-block">{{ field.errors }}</span>
+                                {% endif %}
+                            </div>
+                        {% endfor %}
+                    </div>
+                    <div class="col-sm-6">
+                        <div class="box-header">
+                            <h3>Study data</h3>
+                        </div>
+                        {% for field in study_subject_form %}
                             <div class="form-group {% if field.errors %}has-error{% endif %}">
                                 <label class="col-sm-4 control-label">
                                     {{ field.label }}
diff --git a/smash/web/tests/api_views/test_appointment.py b/smash/web/tests/api_views/test_appointment.py
index a5becb87..8e73b875 100644
--- a/smash/web/tests/api_views/test_appointment.py
+++ b/smash/web/tests/api_views/test_appointment.py
@@ -14,9 +14,9 @@ from web.views.appointment import APPOINTMENT_LIST_GENERIC, APPOINTMENT_LIST_APP
 from web.views.notifications import get_today_midnight_date
 
 
-class TestApi(TestCase):
+class TestAppointmentApi(TestCase):
     def setUp(self):
-        self.subject = create_study_subject()
+        self.study_subject = create_study_subject()
         self.client = Client()
         username = 'piotr'
         password = 'top_secret'
@@ -31,9 +31,9 @@ class TestApi(TestCase):
 
     def test_appointments_valid(self):
         name = "Piotrek"
-        self.subject.first_name = name
-        self.subject.save()
-        visit = create_visit(self.subject)
+        self.study_subject.subject.first_name = name
+        self.study_subject.subject.save()
+        visit = create_visit(self.study_subject)
         create_appointment(visit)
         appointment2 = create_appointment(visit, get_today_midnight_date())
         appointment2.visit = None
@@ -50,9 +50,9 @@ class TestApi(TestCase):
 
     def test_appointments_approaching(self):
         name = "Piotrek"
-        self.subject.first_name = name
-        self.subject.save()
-        visit = create_visit(self.subject)
+        self.study_subject.subject.first_name = name
+        self.study_subject.subject.save()
+        visit = create_visit(self.study_subject)
         create_appointment(visit, get_today_midnight_date() + datetime.timedelta(days=2))
 
         url = reverse('web.api.appointments', kwargs={'type': APPOINTMENT_LIST_APPROACHING})
@@ -63,9 +63,9 @@ class TestApi(TestCase):
 
     def test_appointments_unfinished(self):
         name = "Piotrek"
-        self.subject.first_name = name
-        self.subject.save()
-        visit = create_visit(self.subject)
+        self.study_subject.subject.first_name = name
+        self.study_subject.subject.save()
+        visit = create_visit(self.study_subject)
         create_appointment(visit, get_today_midnight_date() + datetime.timedelta(days=-12))
 
         url = reverse('web.api.appointments', kwargs={'type': APPOINTMENT_LIST_UNFINISHED})
@@ -76,9 +76,9 @@ class TestApi(TestCase):
 
     def test_get_calendar_appointments(self):
         name = "Peter"
-        self.subject.first_name = name
-        self.subject.save()
-        visit = create_visit(self.subject)
+        self.study_subject.subject.first_name = name
+        self.study_subject.subject.save()
+        visit = create_visit(self.study_subject)
         appointment = create_appointment(visit, get_today_midnight_date())
         appointment.save()
 
diff --git a/smash/web/tests/api_views/test_subject.py b/smash/web/tests/api_views/test_subject.py
index bc883180..c7ea2361 100644
--- a/smash/web/tests/api_views/test_subject.py
+++ b/smash/web/tests/api_views/test_subject.py
@@ -38,8 +38,8 @@ class TestApi(TestCase):
 
         self.assertFalse(city_name in cities)
 
-        self.study_subject.city = city_name
-        self.study_subject.save()
+        self.study_subject.subject.city = city_name
+        self.study_subject.subject.save()
 
         response = self.client.get(reverse('web.api.cities'))
         cities = json.loads(response.content)['cities']
@@ -82,8 +82,8 @@ class TestApi(TestCase):
 
     def test_subjects_general_search(self):
         name = "Piotrek"
-        self.study_subject.first_name = name
-        self.study_subject.save()
+        self.study_subject.subject.first_name = name
+        self.study_subject.subject.save()
 
         params = {
             "columns[0][search][value]": "another_name",
@@ -138,12 +138,12 @@ class TestApi(TestCase):
 
     def test_subjects_sort_date_born(self):
         subject = self.study_subject
-        subject.date_born = get_today_midnight_date()
-        subject.save()
+        subject.subject.date_born = get_today_midnight_date()
+        subject.subject.save()
 
         subject2 = create_study_subject(2)
-        subject2.date_born = get_today_midnight_date() + datetime.timedelta(days=1)
-        subject2.save()
+        subject2.subject.date_born = get_today_midnight_date() + datetime.timedelta(days=1)
+        subject2.subject.save()
 
         self.check_subject_ordered("date_born", [subject, subject2])
 
@@ -165,12 +165,12 @@ class TestApi(TestCase):
 
     def test_subjects_sort_last_name(self):
         subject = self.study_subject
-        subject.last_name = "XXX"
-        subject.save()
+        subject.subject.last_name = "XXX"
+        subject.subject.save()
 
         subject2 = create_study_subject(2)
-        subject2.last_name = "YYY"
-        subject2.save()
+        subject2.subject.last_name = "YYY"
+        subject2.subject.save()
 
         self.check_subject_ordered("last_name", [subject, subject2])
 
@@ -243,12 +243,12 @@ class TestApi(TestCase):
 
     def test_subjects_filter_last_name(self):
         subject = self.study_subject
-        subject.last_name = "XXX"
-        subject.save()
+        subject.subject.last_name = "XXX"
+        subject.subject.save()
 
         subject2 = create_study_subject(2)
-        subject2.last_name = "YYY"
-        subject2.save()
+        subject2.subject.last_name = "YYY"
+        subject2.subject.save()
 
         self.check_subject_filtered([["last_name", "Q"]], [])
 
@@ -297,8 +297,6 @@ class TestApi(TestCase):
 
     def test_subjects_filter_visit_1_DONE(self):
         subject = self.study_subject
-        subject.dead = True
-        subject.save()
 
         visit = create_visit(subject)
         appointment = create_appointment(visit)
@@ -317,8 +315,6 @@ class TestApi(TestCase):
 
     def test_subjects_filter_visit_1_MISSED(self):
         subject = self.study_subject
-        subject.dead = True
-        subject.save()
 
         visit = create_visit(subject)
         appointment = create_appointment(visit)
@@ -337,8 +333,6 @@ class TestApi(TestCase):
 
     def test_subjects_filter_visit_1_EXCEED(self):
         subject = self.study_subject
-        subject.dead = True
-        subject.save()
 
         visit = create_visit(subject)
         visit.datetime_begin = get_today_midnight_date() + datetime.timedelta(days=-365 * 2)
@@ -356,8 +350,6 @@ class TestApi(TestCase):
 
     def test_subjects_filter_visit_1_IN_PROGRESS(self):
         subject = self.study_subject
-        subject.dead = True
-        subject.save()
 
         visit = create_visit(subject)
         appointment = create_appointment(visit)
@@ -375,8 +367,6 @@ class TestApi(TestCase):
 
     def test_subjects_filter_visit_1_SHOULD_BE_IN_PROGRESS(self):
         subject = self.study_subject
-        subject.dead = True
-        subject.save()
 
         visit = create_visit(subject)
 
@@ -391,8 +381,6 @@ class TestApi(TestCase):
 
     def test_subjects_filter_visit_1_UPCOMING(self):
         subject = self.study_subject
-        subject.dead = True
-        subject.save()
 
         visit = create_visit(subject)
         visit.datetime_begin = get_today_midnight_date() + datetime.timedelta(days=2)
@@ -410,7 +398,6 @@ class TestApi(TestCase):
 
     def test_subjects_filter_visit_1_visit_2_combined(self):
         subject = self.study_subject
-        subject.save()
 
         visit = create_visit(subject)
         appointment = create_appointment(visit)
diff --git a/smash/web/tests/forms/test_StudySubjectAddForm.py b/smash/web/tests/forms/test_StudySubjectAddForm.py
index 770033cb..a417a5bb 100644
--- a/smash/web/tests/forms/test_StudySubjectAddForm.py
+++ b/smash/web/tests/forms/test_StudySubjectAddForm.py
@@ -1,7 +1,7 @@
 import logging
 
 from web.forms import StudySubjectAddForm, get_new_screening_number
-from web.models.constants import SEX_CHOICES_MALE, SUBJECT_TYPE_CHOICES_CONTROL, COUNTRY_AFGHANISTAN_ID
+from web.models.constants import SUBJECT_TYPE_CHOICES_CONTROL
 from web.tests import LoggedInWithWorkerTestCase
 from web.tests.functions import create_study_subject, create_subject
 
@@ -14,14 +14,12 @@ class StudySubjectAddFormTests(LoggedInWithWorkerTestCase):
 
         location = self.worker.locations.all()[0]
         self.subject = create_subject()
-        self.sample_data = {'first_name': 'name',
-                            'last_name': 'name',
-                            'type': SUBJECT_TYPE_CHOICES_CONTROL,
-                            'default_location': location.id,
-                            'screening_number': "123",
-                            'country': COUNTRY_AFGHANISTAN_ID,
-                            'subject': self.subject.id
-                            }
+        self.sample_data = {
+            'type': SUBJECT_TYPE_CHOICES_CONTROL,
+            'default_location': location.id,
+            'screening_number': "123",
+            'subject': self.subject.id
+        }
 
     def test_validation(self):
         form = StudySubjectAddForm(data=self.sample_data, user=self.user)
@@ -34,6 +32,7 @@ class StudySubjectAddFormTests(LoggedInWithWorkerTestCase):
 
         form = StudySubjectAddForm(data=form_data, user=self.user)
         form.is_valid()
+        form.instance.subject_id = self.subject.id
         self.assertTrue(form.is_valid())
         self.assertIsNone(form.fields['year_of_diagnosis'].initial)
         form.save()
@@ -50,6 +49,7 @@ class StudySubjectAddFormTests(LoggedInWithWorkerTestCase):
         form = StudySubjectAddForm(data=form_data, user=self.user)
         form.is_valid()
         self.assertTrue(form.is_valid())
+        form.instance.subject_id = self.subject.id
         form.save()
 
         form_data['screening_number'] = "2"
@@ -65,6 +65,7 @@ class StudySubjectAddFormTests(LoggedInWithWorkerTestCase):
         form = StudySubjectAddForm(data=form_data, user=self.user)
         form.is_valid()
         self.assertTrue(form.is_valid())
+        form.instance.subject_id = self.subject.id
         form.save()
 
         form_data['screening_number'] = "2"
diff --git a/smash/web/tests/forms/test_StudySubjectEditForm.py b/smash/web/tests/forms/test_StudySubjectEditForm.py
index 6749aba7..f8662f91 100644
--- a/smash/web/tests/forms/test_StudySubjectEditForm.py
+++ b/smash/web/tests/forms/test_StudySubjectEditForm.py
@@ -1,71 +1,62 @@
+import logging
+
 from web.forms import StudySubjectAddForm
 from web.forms import StudySubjectEditForm
 from web.models import StudySubject
-from web.models.constants import SEX_CHOICES_MALE, SUBJECT_TYPE_CHOICES_CONTROL, COUNTRY_AFGHANISTAN_ID
+from web.models.constants import SUBJECT_TYPE_CHOICES_CONTROL
 from web.tests import LoggedInWithWorkerTestCase
-from web.tests.functions import create_subject
+from web.tests.functions import create_subject, create_location, create_study_subject
+
+logger = logging.getLogger(__name__)
 
 
 class StudySubjectEditFormTests(LoggedInWithWorkerTestCase):
     def setUp(self):
         super(StudySubjectEditFormTests, self).setUp()
-        self.subject = create_subject()
+        self.study_subject = create_study_subject()
 
         location = self.worker.locations.all()[0]
-        self.sample_data = {'first_name': 'name',
-                            'last_name': 'name',
-                            'type': SUBJECT_TYPE_CHOICES_CONTROL,
-                            'default_location': location.id,
-                            'country': COUNTRY_AFGHANISTAN_ID,
-                            'screening_number': '123',
-                            'nd_number': 'ND0123',
-                            'subject': self.subject.id
-                            }
+        self.sample_data = {
+            'type': self.study_subject.type,
+            'default_location': location.id,
+            'screening_number': self.study_subject.screening_number,
+            'nd_number': self.study_subject.nd_number,
+            'subject': self.study_subject.subject.id,
+            'id': self.study_subject.id
+        }
 
     def tearDown(self):
         StudySubject.objects.all().delete()
 
     def test_validation(self):
-        add_form = StudySubjectAddForm(data=self.sample_data, user=self.user)
-        subject = add_form.save()
-        self.sample_data['id'] = subject.id
-
         edit_form = StudySubjectEditForm(self.sample_data)
         save_status = edit_form.is_valid()
         self.assertTrue(save_status)
 
     def test_invalid_nd_number_edit(self):
-        add_form = StudySubjectAddForm(data=self.sample_data, user=self.user)
-        add_form.save()
+        study_subject2 = create_study_subject(124)
+        study_subject2.nd_number = "ND0124"
+        study_subject2.screening_number = "124"
+        study_subject2.save()
 
         self.sample_data['nd_number'] = "ND0124"
-        self.sample_data['screening_number'] = "124"
-        add_form = StudySubjectAddForm(data=self.sample_data, user=self.user)
-        subject = add_form.save()
-
-        self.sample_data['id'] = subject.id
-        self.sample_data['nd_number'] = "ND0123"
         edit_form = StudySubjectEditForm(self.sample_data)
 
         save_status = edit_form.is_valid()
+        self.assertTrue("nd_number" in edit_form.errors)
         self.assertFalse(save_status)
 
     def test_invalid_mpower_id_edit(self):
-        self.sample_data['screening_number'] = "001"
-        add_form = StudySubjectAddForm(data=self.sample_data, user=self.user)
-        subject = add_form.save()
-
-        self.sample_data['mpower_id'] = "mpower_002"
-        self.sample_data['nd_number'] = "ND0002"
-        self.sample_data['screening_number'] = "002"
-        add_form = StudySubjectAddForm(data=self.sample_data, user=self.user)
-        add_form.save()
+        self.study_subject.mpower_id = "mpower_002"
+        self.study_subject.nd_number = "ND0002"
+        self.study_subject.screening_number = "002"
+        self.study_subject.save()
 
-        self.sample_data['id'] = subject.id
         self.sample_data['mpower_id'] = "mpower_002"
         self.sample_data['nd_number'] = "ND0001"
         self.sample_data['screening_number'] = "001"
         edit_form = StudySubjectEditForm(self.sample_data)
 
         save_status = edit_form.is_valid()
+        self.assertTrue("mpower_id" in edit_form.errors)
         self.assertFalse(save_status)
diff --git a/smash/web/tests/functions.py b/smash/web/tests/functions.py
index 8c835428..adb1eaf8 100644
--- a/smash/web/tests/functions.py
+++ b/smash/web/tests/functions.py
@@ -67,12 +67,9 @@ def create_study_subject(subject_id=1, subject=None):
     if subject is None:
         subject = create_subject()
     return StudySubject.objects.create(
-        first_name="Piotr",
-        last_name="Gawron",
         default_location=get_test_location(),
         type=SUBJECT_TYPE_CHOICES_CONTROL,
         screening_number="piotr's number" + str(subject_id),
-        country_id=COUNTRY_AFGHANISTAN_ID,
         subject=subject
     )
 
diff --git a/smash/web/tests/models/test_mail_template.py b/smash/web/tests/models/test_mail_template.py
index 53f8b2f1..49c84a13 100644
--- a/smash/web/tests/models/test_mail_template.py
+++ b/smash/web/tests/models/test_mail_template.py
@@ -7,7 +7,8 @@ from web.models import MailTemplate
 from web.models.constants import MAIL_TEMPLATE_CONTEXT_APPOINTMENT, MAIL_TEMPLATE_CONTEXT_VISIT, \
     MAIL_TEMPLATE_CONTEXT_SUBJECT
 from web.models.mail_template import DATE_FORMAT_SHORT
-from web.tests.functions import create_language, get_resource_path, create_appointment, create_user, create_study_subject, \
+from web.tests.functions import create_language, get_resource_path, create_appointment, create_user, \
+    create_study_subject, \
     create_visit
 
 
@@ -89,7 +90,7 @@ class MailTemplateModelTests(TestCase):
         doc = Document(stream)
         worker_name = str(self.user.worker)
 
-        self.check_doc_contains(doc, [worker_name, str(subject), str(subject.country), subject.nd_number,
+        self.check_doc_contains(doc, [worker_name, str(subject), str(subject.subject.country), subject.nd_number,
                                       subject.get_type_display()])
 
     def test_apply_visit(self):
@@ -103,7 +104,8 @@ class MailTemplateModelTests(TestCase):
         doc = Document(stream)
         worker_name = str(self.user.worker)
 
-        self.check_doc_contains(doc, [worker_name, str(visit.subject), str(visit.subject.country), visit.subject.nd_number,
+        self.check_doc_contains(doc, [worker_name, str(visit.subject), str(visit.subject.subject.country),
+                                      visit.subject.nd_number,
                                       visit.subject.get_type_display(),
                                       visit.datetime_begin.strftime(DATE_FORMAT_SHORT),
                                       visit.datetime_end.strftime(DATE_FORMAT_SHORT)])
diff --git a/smash/web/tests/models/test_visit.py b/smash/web/tests/models/test_visit.py
index b92a51ba..a247d838 100644
--- a/smash/web/tests/models/test_visit.py
+++ b/smash/web/tests/models/test_visit.py
@@ -2,10 +2,9 @@ import datetime
 
 from django.test import TestCase
 
-from web.models.constants import SUBJECT_TYPE_CHOICES_PATIENT
 from web.models import Visit
+from web.models.constants import SUBJECT_TYPE_CHOICES_PATIENT
 from web.tests.functions import create_study_subject, create_visit
-from web.views.notifications import get_today_midnight_date
 
 
 class VisitModelTests(TestCase):
diff --git a/smash/web/tests/test_RedcapConnector.py b/smash/web/tests/test_RedcapConnector.py
index 61ee984e..bde702f4 100644
--- a/smash/web/tests/test_RedcapConnector.py
+++ b/smash/web/tests/test_RedcapConnector.py
@@ -72,16 +72,16 @@ class TestRedcapConnector(TestCase):
 
     def test_create_inconsistent_data_for_date_born(self):
         prepare_test_redcap_connection()
-        subject = create_study_subject()
+        study_subject = create_study_subject()
 
-        redcap_subject = self.create_redcap_subject_from_smash_subject(subject)
-        subject.date_born = get_today_midnight_date()
+        redcap_subject = self.create_redcap_subject_from_smash_subject(study_subject)
+        study_subject.subject.date_born = get_today_midnight_date()
 
-        self.check_single_inconsistency(redcap_subject, subject)
+        self.check_single_inconsistency(redcap_subject, study_subject)
 
-    def check_single_inconsistency(self, redcap_subject, subject):
+    def check_single_inconsistency(self, redcap_subject, study_subject):
         redcap_connection = RedcapConnector()
-        result = redcap_connection.create_inconsistency_subject(redcap_subject, subject, "")
+        result = redcap_connection.create_inconsistency_subject(redcap_subject, study_subject, "")
         self.assertIsNotNone(result)
         self.assertEqual(1, len(result.fields), "Invalid number of fields. Found: " + str(result.fields))
 
@@ -98,12 +98,12 @@ class TestRedcapConnector(TestCase):
         language = Language.objects.create(name="xx")
         language.save()
         prepare_test_redcap_connection()
-        subject = create_study_subject()
+        study_subject = create_study_subject()
 
-        redcap_subject = self.create_redcap_subject_from_smash_subject(subject)
-        subject.languages.add(language)
+        redcap_subject = self.create_redcap_subject_from_smash_subject(study_subject)
+        study_subject.subject.languages.add(language)
 
-        self.check_single_inconsistency(redcap_subject, subject)
+        self.check_single_inconsistency(redcap_subject, study_subject)
 
     def test_create_inconsistent_data_for_language2(self):
         language = Language.objects.create(name="xx")
@@ -139,11 +139,11 @@ class TestRedcapConnector(TestCase):
     @staticmethod
     def create_redcap_subject_from_smash_subject(study_subject):
         redcap_subject = RedcapSubject()
-        for language in study_subject.languages.all():
+        for language in study_subject.subject.languages.all():
             redcap_subject.add_language(language)
         redcap_subject.mpower_id = study_subject.mpower_id
         redcap_subject.dead = study_subject.subject.dead
-        redcap_subject.date_born = study_subject.date_born
+        redcap_subject.date_born = study_subject.subject.date_born
         redcap_subject.nd_number = study_subject.nd_number
         redcap_subject.sex = study_subject.subject.sex
         return redcap_subject
diff --git a/smash/web/tests/view/test_appointments.py b/smash/web/tests/view/test_appointments.py
index 31045c70..bad1cfee 100644
--- a/smash/web/tests/view/test_appointments.py
+++ b/smash/web/tests/view/test_appointments.py
@@ -3,12 +3,13 @@ import logging
 
 from django.urls import reverse
 
-from web.tests.functions import create_study_subject, create_visit, create_appointment, create_worker, create_flying_team, \
-    format_form_field
-from web.forms import AppointmentEditForm, StudySubjectEditForm
+from web.forms import AppointmentEditForm, StudySubjectEditForm, SubjectEditForm
 from web.models import Appointment, StudySubject
-from web.views.notifications import get_today_midnight_date
 from web.tests import LoggedInTestCase
+from web.tests.functions import create_study_subject, create_visit, create_appointment, create_worker, \
+    create_flying_team, \
+    format_form_field
+from web.views.notifications import get_today_midnight_date
 
 logger = logging.getLogger(__name__)
 
@@ -29,15 +30,7 @@ class AppointmentsViewTests(LoggedInTestCase):
         new_comment = 'new comment'
         new_status = appointment.APPOINTMENT_STATUS_NO_SHOW
         new_last_name = "new last name"
-        form_appointment = AppointmentEditForm(user=self.user, instance=appointment, prefix="appointment")
-        form_subject = StudySubjectEditForm(instance=subject, prefix="subject")
-        form_data = {}
-        for key, value in form_appointment.initial.items():
-            if value is not None:
-                form_data['appointment-{}'.format(key)] = value
-        for key, value in form_subject.initial.items():
-            if value is not None:
-                form_data['subject-{}'.format(key)] = value
+        form_data = self.prepare_form(appointment, subject)
         form_data["appointment-comment"] = new_comment
         form_data["appointment-status"] = new_status
         form_data["subject-last_name"] = new_last_name
@@ -48,7 +41,7 @@ class AppointmentsViewTests(LoggedInTestCase):
         updated_subject = StudySubject.objects.filter(id=subject.id)[0]
         self.assertEqual(new_comment, updated_appointment.comment)
         self.assertEqual(new_status, updated_appointment.status)
-        self.assertEqual(new_last_name, updated_subject.last_name)
+        self.assertEqual(new_last_name, updated_subject.subject.last_name)
 
     def test_appointments_edit_without_visit(self):
         appointment = create_appointment()
@@ -113,7 +106,7 @@ class AppointmentsViewTests(LoggedInTestCase):
 
         form_data = self.prepare_form(appointment, subject)
         form_data["appointment-status"] = Appointment.APPOINTMENT_STATUS_FINISHED
-        form_data["subject-nd_number"] = "ND9999"
+        form_data["study-subject-nd_number"] = "ND9999"
 
         response = self.client.post(
             reverse('web.views.appointment_edit', kwargs={'id': appointment.id}), data=form_data)
@@ -125,11 +118,15 @@ class AppointmentsViewTests(LoggedInTestCase):
 
     def prepare_form(self, appointment, subject):
         form_appointment = AppointmentEditForm(user=self.user, instance=appointment, prefix="appointment")
-        form_subject = StudySubjectEditForm(instance=subject, prefix="subject")
+        form_study_subject = StudySubjectEditForm(instance=subject, prefix="study-subject")
+        form_subject = SubjectEditForm(instance=subject.subject, prefix="study-subject")
         form_data = {}
         for key, value in form_appointment.initial.items():
             if value is not None:
                 form_data['appointment-{}'.format(key)] = format_form_field(value)
+        for key, value in form_study_subject.initial.items():
+            if value is not None:
+                form_data['study-subject-{}'.format(key)] = format_form_field(value)
         for key, value in form_subject.initial.items():
             if value is not None:
                 form_data['subject-{}'.format(key)] = format_form_field(value)
@@ -144,7 +141,7 @@ class AppointmentsViewTests(LoggedInTestCase):
         form_data["appointment-status"] = Appointment.APPOINTMENT_STATUS_FINISHED
         form_data["appointment-flying_team"] = create_flying_team().id
         form_data['appointment-status'] = Appointment.APPOINTMENT_STATUS_FINISHED
-        form_data["subject-nd_number"] = "ND9999"
+        form_data["study-subject-nd_number"] = "ND9999"
 
         self.client.post(reverse('web.views.appointment_edit', kwargs={'id': appointment.id}), data=form_data)
 
diff --git a/smash/web/tests/view/test_visit.py b/smash/web/tests/view/test_visit.py
index c1c5cce7..d43c5d15 100644
--- a/smash/web/tests/view/test_visit.py
+++ b/smash/web/tests/view/test_visit.py
@@ -36,9 +36,9 @@ class VisitViewTests(LoggedInTestCase):
         self.assertNotContains(response, "error")
 
     def test_render_add_visit(self):
-        subject = create_study_subject()
+        study_subject = create_study_subject()
 
-        response = self.client.get(reverse('web.views.visit_add', kwargs={'subject_id': subject.id}))
+        response = self.client.get(reverse('web.views.visit_add', kwargs={'subject_id': study_subject.id}))
         self.assertEqual(response.status_code, 200)
 
     def test_save_add_visit(self):
diff --git a/smash/web/views/appointment.py b/smash/web/views/appointment.py
index 910c5839..b351e86e 100644
--- a/smash/web/views/appointment.py
+++ b/smash/web/views/appointment.py
@@ -7,7 +7,8 @@ from django.core.exceptions import ValidationError
 from django.shortcuts import get_object_or_404, redirect
 
 from . import wrap_response
-from ..forms import AppointmentDetailForm, AppointmentAddForm, AppointmentEditForm, StudySubjectEditForm
+from ..forms import AppointmentDetailForm, AppointmentAddForm, AppointmentEditForm, StudySubjectEditForm, \
+    SubjectEditForm
 from ..models import Appointment, StudySubject, MailTemplate
 
 APPOINTMENT_LIST_GENERIC = "GENERIC"
@@ -58,6 +59,7 @@ def appointment_add(request, visit_id=None):
 
 def appointment_edit(request, id):
     the_appointment = get_object_or_404(Appointment, id=id)
+    study_subject_form = None
     subject_form = None
     contact_attempts = None
 
@@ -69,7 +71,12 @@ def appointment_edit(request, id):
                                                prefix="appointment")
         is_valid_form = True
         if the_appointment.visit is not None:
-            subject_form = StudySubjectEditForm(request.POST, instance=the_appointment.visit.subject, prefix="subject")
+            study_subject_form = StudySubjectEditForm(request.POST, instance=the_appointment.visit.subject,
+                                                      prefix="study-subject")
+            if not study_subject_form.is_valid():
+                is_valid_form = False
+            subject_form = SubjectEditForm(request.POST, instance=the_appointment.visit.subject.subject,
+                                           prefix="subject")
             if not subject_form.is_valid():
                 is_valid_form = False
 
@@ -78,13 +85,14 @@ def appointment_edit(request, id):
 
         if the_appointment.visit is not None:
             if appointment_form.cleaned_data["status"] == Appointment.APPOINTMENT_STATUS_FINISHED:
-                if re.match('ND[0-9][0-9][0-9][0-9]', subject_form.cleaned_data["nd_number"]) is None:
-                    subject_form.add_error('nd_number', ValidationError("invalid ND number"))
+                if re.match('ND[0-9][0-9][0-9][0-9]', study_subject_form.cleaned_data["nd_number"]) is None:
+                    study_subject_form.add_error('nd_number', ValidationError("invalid ND number"))
                     is_valid_form = False
 
         if is_valid_form:
             appointment_form.save()
-            if subject_form is not None:
+            if study_subject_form is not None:
+                study_subject_form.save()
                 subject_form.save()
             the_appointment = get_object_or_404(Appointment, id=id)
 
@@ -109,17 +117,20 @@ def appointment_edit(request, id):
         appointment_form = AppointmentEditForm(instance=the_appointment, user=request.user, prefix="appointment")
 
         if the_appointment.visit is not None:
-            subject_form = StudySubjectEditForm(instance=the_appointment.visit.subject, prefix="subject")
+            study_subject_form = StudySubjectEditForm(instance=the_appointment.visit.subject, prefix="subject")
+            subject_form = SubjectEditForm(instance=the_appointment.visit.subject.subject,
+                                           prefix="subject")
             contact_attempts = the_appointment.visit.subject.contactattempt_set.order_by('-datetime_when').all()
 
     languages = []
     if the_appointment.visit is not None:
-        subject = the_appointment.visit.subject
+        subject = the_appointment.visit.subject.subject
         if subject.default_written_communication_language:
             languages.append(subject.default_written_communication_language)
         languages.extend(subject.languages.all())
     return wrap_response(request, 'appointments/edit.html', {
-        'form': appointment_form,
+        'appointment_form': appointment_form,
+        'study_subject_form': study_subject_form,
         'subject_form': subject_form,
         'id': id,
         'appointment': the_appointment,
diff --git a/smash/web/views/export.py b/smash/web/views/export.py
index e99ad384..b5b755e6 100644
--- a/smash/web/views/export.py
+++ b/smash/web/views/export.py
@@ -7,7 +7,7 @@ from django.http import HttpResponse
 
 from notifications import get_today_midnight_date
 from . import e500_error, wrap_response
-from ..models import StudySubject, Appointment
+from ..models import Subject, StudySubject, Appointment
 
 
 @login_required
@@ -65,28 +65,31 @@ def get_subjects_as_array():
 
     result.append(field_names)
 
-    subjects = StudySubject.objects.order_by('-last_name')
+    subjects = StudySubject.objects.order_by('-subject__last_name')
     for subject in subjects:
         row = subject_to_row_for_fields(subject, subject_fields)
         result.append([unicode(s).replace("\n", ";").replace("\r", ";") for s in row])
     return result
 
 
-def subject_to_row_for_fields(subject, subject_fields):
+def subject_to_row_for_fields(study_subject, subject_fields):
     row = []
     for field in subject_fields:
         if field == DROP_OUT_FIELD:
-            if not subject.resigned:
+            if not study_subject.resigned:
                 cell = False
             else:
-                finished_appointments = Appointment.objects.filter(visit__subject=subject).filter(
+                finished_appointments = Appointment.objects.filter(visit__subject=study_subject).filter(
                     status=Appointment.APPOINTMENT_STATUS_FINISHED).count()
                 if finished_appointments > 0:
                     cell = True
                 else:
                     cell = False
         else:
-            cell = getattr(subject, field.name)
+            if hasattr(study_subject, field.name):
+                cell = getattr(study_subject, field.name)
+            elif hasattr(study_subject.subject, field.name):
+                cell = getattr(study_subject.subject, field.name)
             if cell is None:
                 cell = ""
         row.append(cell)
@@ -95,9 +98,12 @@ def subject_to_row_for_fields(subject, subject_fields):
 
 def get_default_subject_fields():
     subject_fields = []
-    for field in StudySubject._meta.fields:
+    for field in Subject._meta.fields:
         if field.name != "ID":
             subject_fields.append(field)
+    for field in StudySubject._meta.fields:
+        if field.name != "ID" and field.name != "subject":
+            subject_fields.append(field)
     subject_fields.append(DROP_OUT_FIELD)
     return subject_fields
 
@@ -121,8 +127,8 @@ def get_appointments_as_array():
 
     for appointment in appointments:
         if appointment.visit is not None:
-            row = [appointment.visit.subject.nd_number, appointment.visit.subject.last_name,
-                   appointment.visit.subject.first_name, appointment.visit.visit_number]
+            row = [appointment.visit.subject.nd_number, appointment.visit.subject.subject.last_name,
+                   appointment.visit.subject.subject.first_name, appointment.visit.visit_number]
         else:
             row = ["---", "---", "---", "---"]
         for field in appointments_fields:
diff --git a/smash/web/views/subject.py b/smash/web/views/subject.py
index 2db7e9d9..53ceafe6 100644
--- a/smash/web/views/subject.py
+++ b/smash/web/views/subject.py
@@ -29,8 +29,9 @@ def subject_add(request):
 
         subject_form = SubjectAddForm(request.POST, request.FILES, prefix="subject")
         if study_subject_form.is_valid() and subject_form.is_valid():
+            subject = subject_form.save()
+            study_subject_form.instance.subject_id = subject.id
             study_subject_form.save()
-            subject_form.save()
             messages.add_message(request, messages.SUCCESS, 'Subject created')
             return redirect('web.views.subject_edit', id=study_subject_form.instance.id)
         else:
@@ -90,9 +91,9 @@ def subject_edit(request, id):
         subject_form = SubjectEditForm(instance=study_subject.subject, was_dead=was_dead, prefix="subject")
 
     languages = []
-    if study_subject.default_written_communication_language:
-        languages.append(study_subject.default_written_communication_language)
-    languages.extend(study_subject.languages.all())
+    if study_subject.subject.default_written_communication_language:
+        languages.append(study_subject.subject.default_written_communication_language)
+    languages.extend(study_subject.subject.languages.all())
 
     return wrap_response(request, 'subjects/edit.html', {
         'study_subject_form': study_subject_form,
diff --git a/smash/web/views/visit.py b/smash/web/views/visit.py
index 5aa0e6d1..0de64bba 100644
--- a/smash/web/views/visit.py
+++ b/smash/web/views/visit.py
@@ -51,7 +51,7 @@ def visit_details(request, id):
 
     visit_finished = displayed_visit.is_finished
     visit_id = displayed_visit.id
-    displayed_subject = displayed_visit.subject
+    study_subject = displayed_visit.subject
     list_of_appointments = displayed_visit.appointment_set.all()
 
     can_finish = not waiting_for_appointment(displayed_visit)
@@ -60,11 +60,11 @@ def visit_details(request, id):
         if appointment.status == Appointment.APPOINTMENT_STATUS_SCHEDULED:
             can_finish = False
 
-    subject_form = SubjectDetailForm(instance=displayed_subject)
+    subject_form = SubjectDetailForm(instance=study_subject)
     languages = []
-    if displayed_subject.default_written_communication_language:
-        languages.append(displayed_subject.default_written_communication_language)
-    languages.extend(displayed_subject.languages.all())
+    if study_subject.subject.default_written_communication_language:
+        languages.append(study_subject.subject.default_written_communication_language)
+    languages.extend(study_subject.subject.languages.all())
 
     return wrap_response(request, 'visits/details.html', {
         'vform': visit_form,
-- 
GitLab