diff --git a/smash/web/forms/study_forms.py b/smash/web/forms/study_forms.py
index 76c51a4288da0395d45e580bfa75ad5f689696e1..916f2316a4ff0c3f41a9f75840ea383a4d668bdb 100644
--- a/smash/web/forms/study_forms.py
+++ b/smash/web/forms/study_forms.py
@@ -1,8 +1,7 @@
 import logging
 
-from django.forms import ModelForm
-
-from web.models import Study, StudyNotificationParameters, StudyColumns
+from django.forms import ModelForm, ValidationError
+from web.models import Study, StudyNotificationParameters, StudyColumns, StudySubject
 
 logger = logging.getLogger(__name__)
 
@@ -12,6 +11,16 @@ class StudyEditForm(ModelForm):
     def __init__(self, *args, **kwargs):
         super(StudyEditForm, self).__init__(*args, **kwargs)
 
+    def clean_nd_number_study_subject_regex(self):
+        nd_number_study_subject_regex = self.cleaned_data.get(
+            'nd_number_study_subject_regex')
+
+        if StudySubject.check_nd_number_regex(nd_number_study_subject_regex) == False:
+            raise ValidationError(
+                'Please enter a valid nd_number_study_subject_regex regex.')
+
+        return nd_number_study_subject_regex
+
     class Meta:
         model = Study
         fields = '__all__'
@@ -21,7 +30,8 @@ class StudyEditForm(ModelForm):
 class StudyNotificationParametersEditForm(ModelForm):
 
     def __init__(self, *args, **kwargs):
-        super(StudyNotificationParametersEditForm, self).__init__(*args, **kwargs)
+        super(StudyNotificationParametersEditForm,
+              self).__init__(*args, **kwargs)
 
     class Meta:
         model = StudyNotificationParameters
diff --git a/smash/web/forms/study_subject_forms.py b/smash/web/forms/study_subject_forms.py
index 44afb25786f47a3d43e6a7f56a9ea1387ccbdab6..76d4d7735119ae75280a3e7a42550d051879c632 100644
--- a/smash/web/forms/study_subject_forms.py
+++ b/smash/web/forms/study_subject_forms.py
@@ -197,7 +197,7 @@ def validate_subject_nd_number(self, cleaned_data):
     if self.study.columns.nd_number:
         nd_number = cleaned_data['nd_number']
         if nd_number != "":
-            if re.match('ND[0-9][0-9][0-9][0-9]', nd_number) is None:
+            if not self.study.check_nd_number(nd_number):
                 self.add_error('nd_number', "Invalid ND number")
             else:
                 subjects_from_db = StudySubject.objects.filter(nd_number=nd_number, study=self.study)
diff --git a/smash/web/migrations/0119_auto_20181024_1158.py b/smash/web/migrations/0119_auto_20181024_1158.py
new file mode 100644
index 0000000000000000000000000000000000000000..cab12fa337487854b82a8cf770efd1cda340dd36
--- /dev/null
+++ b/smash/web/migrations/0119_auto_20181024_1158.py
@@ -0,0 +1,25 @@
+# -*- coding: utf-8 -*-
+# Generated by Django 1.11.5 on 2018-10-24 11:58
+from __future__ import unicode_literals
+
+from django.db import migrations, models
+
+
+class Migration(migrations.Migration):
+
+    dependencies = [
+        ('web', '0118_voucher_activity_type'),
+    ]
+
+    operations = [
+        migrations.AlterField(
+            model_name='studyvisitlist',
+            name='type',
+            field=models.CharField(choices=[(b'UNFINISHED', b'Unfinished visits'), (b'APPROACHING_WITHOUT_APPOINTMENTS', b'Approaching visits'), (b'APPROACHING_FOR_MAIL_CONTACT', b'Post mail for approaching visits'), (b'GENERIC', b'Generic visit list'), (b'MISSING_APPOINTMENTS', b'Visits with missing appointments'), (b'EXCEEDED_TIME', b'Exceeded visit time')], max_length=50, verbose_name=b'Type of list'),
+        ),
+        migrations.AlterField(
+            model_name='workerstudyrole',
+            name='role',
+            field=models.CharField(choices=[(b'DOCTOR', b'Doctor'), (b'NURSE', b'Nurse'), (b'PSYCHOLOGIST', b'Psychologist'), (b'TECHNICIAN', b'Technician'), (b'SECRETARY', b'Secretary'), (b'PROJECT MANAGER', b'Project Manager')], max_length=20, verbose_name=b'Role'),
+        ),
+    ]
diff --git a/smash/web/migrations/0120_study_nd_number_study_subject_regex.py b/smash/web/migrations/0120_study_nd_number_study_subject_regex.py
new file mode 100644
index 0000000000000000000000000000000000000000..9b4146edb8a1bcdfbf19a3144c4e9b932ee0beb6
--- /dev/null
+++ b/smash/web/migrations/0120_study_nd_number_study_subject_regex.py
@@ -0,0 +1,20 @@
+# -*- coding: utf-8 -*-
+# Generated by Django 1.11.5 on 2018-10-24 12:00
+from __future__ import unicode_literals
+
+from django.db import migrations, models
+
+
+class Migration(migrations.Migration):
+
+    dependencies = [
+        ('web', '0119_auto_20181024_1158'),
+    ]
+
+    operations = [
+        migrations.AddField(
+            model_name='study',
+            name='nd_number_study_subject_regex',
+            field=models.CharField(default=b'^ND\\d{4}$', help_text=b'Defines the regex to check the identification number used for each study subject.', max_length=255, verbose_name=b'Study Subject ND Number Regex'),
+        ),
+    ]
diff --git a/smash/web/migrations/0121_auto_20181024_1859.py b/smash/web/migrations/0121_auto_20181024_1859.py
new file mode 100644
index 0000000000000000000000000000000000000000..2e0b4654936fdae97a6ddc06809d3a89918a17d9
--- /dev/null
+++ b/smash/web/migrations/0121_auto_20181024_1859.py
@@ -0,0 +1,20 @@
+# -*- coding: utf-8 -*-
+# Generated by Django 1.11.5 on 2018-10-24 18:59
+from __future__ import unicode_literals
+
+from django.db import migrations, models
+
+
+class Migration(migrations.Migration):
+
+    dependencies = [
+        ('web', '0120_study_nd_number_study_subject_regex'),
+    ]
+
+    operations = [
+        migrations.AlterField(
+            model_name='study',
+            name='nd_number_study_subject_regex',
+            field=models.CharField(default=b'^ND\\d{4}$', help_text=b'Defines the regex to check the ID used for each study subject. Keep in mind that this regex should be valid for all previous study subjects in the database.', max_length=255, verbose_name=b'Study Subject ND Number Regex'),
+        ),
+    ]
diff --git a/smash/web/models/study.py b/smash/web/models/study.py
index 4501a3be57d712de4cb3f35cf77eae8a9407c67a..831465d00b223c1465a96d11d79a27101c9e31c3 100644
--- a/smash/web/models/study.py
+++ b/smash/web/models/study.py
@@ -3,13 +3,20 @@ from django.db import models
 
 from web.models import StudyColumns, StudyNotificationParameters
 
+import re
+
 
 class Study(models.Model):
+
     class Meta:
         app_label = 'web'
 
     name = models.CharField(max_length=255, verbose_name='Name')
 
+    nd_number_study_subject_regex = models.CharField(
+        max_length=255, verbose_name='Study Subject ND Number Regex', default=r'^ND\d{4}$',
+        help_text='Defines the regex to check the ID used for each study subject. Keep in mind that this regex should be valid for all previous study subjects in the database.')
+
     columns = models.OneToOneField(
         StudyColumns,
         on_delete=models.CASCADE,
@@ -24,8 +31,20 @@ class Study(models.Model):
         verbose_name="Auto create follow up visit"
     )
 
+    def check_nd_number(self, nd_number):
+        regex = re.compile(self.nd_number_study_subject_regex)
+        return regex.match(nd_number) is not None
+
     def __str__(self):
         return "%s" % self.name
 
     def __unicode__(self):
         return "%s" % self.name
+
+    @staticmethod
+    def get_by_id(study_id):
+        study = Study.objects.filter(id=study_id)
+        if len(study) > 0:
+            return study[0]
+        else:
+            return None
diff --git a/smash/web/models/study_subject.py b/smash/web/models/study_subject.py
index 3854138909c993a2dbd98168dffd849b6fa48d97..e62425531401fd2e4808e49797649dbb87625ee4 100644
--- a/smash/web/models/study_subject.py
+++ b/smash/web/models/study_subject.py
@@ -1,5 +1,6 @@
 # coding=utf-8
 import logging
+import re
 from django.db import models
 
 from web.models import VoucherType, Appointment, Location, Visit
@@ -7,7 +8,9 @@ from web.models.constants import BOOL_CHOICES, SUBJECT_TYPE_CHOICES, FILE_STORAG
 
 logger = logging.getLogger(__name__)
 
+
 class StudySubject(models.Model):
+
     class Meta:
         app_label = 'web'
 
@@ -18,7 +21,8 @@ class StudySubject(models.Model):
             visit.save()
 
     def finish_all_appointments(self):
-        appointments = Appointment.objects.filter(visit__subject=self, status=Appointment.APPOINTMENT_STATUS_SCHEDULED)
+        appointments = Appointment.objects.filter(
+            visit__subject=self, status=Appointment.APPOINTMENT_STATUS_SCHEDULED)
         for appointment in appointments:
             appointment.status = Appointment.APPOINTMENT_STATUS_CANCELLED
             appointment.save()
@@ -164,18 +168,28 @@ class StudySubject(models.Model):
         for part in parts:
             chunks = part.strip().split('-')
             if len(chunks) == 2:
-              letter, number = chunks
-              tupl = (letter, int(number))
+                letter, number = chunks
+                tupl = (letter, int(number))
             else:
-              logger.warn('There are {} chunks in some parts of this screening_number: |{}|.'.format(len(chunks), self.screening_number))
-              tupl = (part.strip(), None)
+                logger.warn('There are {} chunks in some parts of this screening_number: |{}|.'.format(
+                    len(chunks), self.screening_number))
+                tupl = (part.strip(), None)
             if pattern is not None and pattern in part:
                 matches.append(tupl)
             else:
                 reminder.append(tupl)
 
         return matches + sorted(reminder, reverse=reverse)
-            
+
+    @staticmethod
+    def check_nd_number_regex(regex_str):
+        nd_numbers = StudySubject.objects.all().values_list('nd_number', flat=True)
+        regex = re.compile(regex_str)
+        for nd_number in nd_numbers:
+            if regex.match(nd_number) is None:
+                return False
+        return True
+
     def __str__(self):
         return "%s %s" % (self.subject.first_name, self.subject.last_name)
 
diff --git a/smash/web/templates/study/edit.html b/smash/web/templates/study/edit.html
index 54be5ce7bf8131024a775eea19c4ca053ee51e5c..e1e8d594d914cae156ec0bbac6bb0b134b9e488b 100644
--- a/smash/web/templates/study/edit.html
+++ b/smash/web/templates/study/edit.html
@@ -6,7 +6,12 @@
     {{ block.super }}
     <!-- DataTables -->
     <link rel="stylesheet" href="{% static 'AdminLTE/plugins/datatables/dataTables.bootstrap.css' %}">
-
+    <style type="text/css">
+        .tooltip-inner {
+            max-width: 350px;
+            width: 350px; 
+        }
+    </style>
     {% include "includes/datepicker.css.html" %}
     {% include "includes/datetimepicker.css.html" %}
 {% endblock styles %}
@@ -45,6 +50,9 @@
                                     <div class="col-md-6 form-group  {% if field.errors %}has-error{% endif %}">
                                         <label for="{# TODO #}" class="col-sm-4 control-label">
                                             {{ field.label }}
+                                            {% if field.help_text %}
+                                                <i class="fa fa-info-circle" aria-hidden="true" data-toggle="tooltip" data-placement="bottom" title="{{field.help_text}}"></i>
+                                            {% endif %}
                                         </label>
 
                                         <div class="col-sm-8">
diff --git a/smash/web/tests/forms/test_study_forms.py b/smash/web/tests/forms/test_study_forms.py
new file mode 100644
index 0000000000000000000000000000000000000000..a150a83c181cee62dcf894648ed7d5bb797a0279
--- /dev/null
+++ b/smash/web/tests/forms/test_study_forms.py
@@ -0,0 +1,40 @@
+from django.test import TestCase
+from django.forms import ValidationError
+from web.tests.functions import create_study_subject
+from web.forms.study_forms import StudyEditForm
+from web.models.study import Study
+from web.models.study_subject import StudySubject
+
+class StudyFormTests(TestCase):
+
+    def test_study_default_regex(self):
+        # this will add a studysubject with a NDnumber
+        StudySubject.objects.all().delete()
+        create_study_subject(nd_number='ND0001')
+        form = StudyEditForm()
+        # set default regex
+        nd_number_study_subject_regex_default = Study._meta.get_field(
+            'nd_number_study_subject_regex').get_default()
+        form.cleaned_data = {
+            'nd_number_study_subject_regex': nd_number_study_subject_regex_default}
+        self.assertTrue(form.clean_nd_number_study_subject_regex()
+                        == nd_number_study_subject_regex_default)
+        # test wrong regex
+        form = StudyEditForm()
+        nd_number_study_subject_regex_default = r'^nd\d{5}$'
+        form.cleaned_data = {
+            'nd_number_study_subject_regex': nd_number_study_subject_regex_default}
+        self.assertRaises(
+            ValidationError, form.clean_nd_number_study_subject_regex)
+
+    def test_study_other_regex(self):
+        StudySubject.objects.all().delete()
+        # this will add a studysubject with a NDnumber
+        create_study_subject(nd_number='nd00001')
+        form = StudyEditForm()
+        # test new regex
+        nd_number_study_subject_regex_default = r'^nd\d{5}$'
+        form.cleaned_data = {
+            'nd_number_study_subject_regex': nd_number_study_subject_regex_default}
+        self.assertTrue(form.clean_nd_number_study_subject_regex()
+                        == nd_number_study_subject_regex_default)
diff --git a/smash/web/tests/functions.py b/smash/web/tests/functions.py
index 3af08171a7a08d4b512468666240737fd8fd0ef2..db061dd7bbe6a33c4b628c3ffd1cfbc6cb65fb66 100644
--- a/smash/web/tests/functions.py
+++ b/smash/web/tests/functions.py
@@ -186,16 +186,22 @@ def create_subject():
     )
 
 
-def create_study_subject(subject_id=1, subject=None):
+def create_study_subject(subject_id=1, subject=None, nd_number='ND0001'):
     if subject is None:
         subject = create_subject()
-    return StudySubject.objects.create(
+    study_subject = StudySubject.objects.create(
         default_location=get_test_location(),
         type=SUBJECT_TYPE_CHOICES_CONTROL,
         screening_number="piotr's number" + str(subject_id),
         study=get_test_study(),
         subject=subject
     )
+    if nd_number is not None:
+        study_subject.nd_number = nd_number
+        study_subject.save()
+
+    return study_subject
+
 
 def create_study_subject_with_multiple_screening_numbers(subject_id=1, subject=None):
     if subject is None:
@@ -242,7 +248,8 @@ def create_worker(user=None, with_test_location=False):
     if with_test_location:
         worker.locations = [get_test_location()]
         worker.save()
-    WorkerStudyRole.objects.create(worker=worker, study_id=GLOBAL_STUDY_ID, role=ROLE_CHOICES_DOCTOR)
+    WorkerStudyRole.objects.create(
+        worker=worker, study_id=GLOBAL_STUDY_ID, role=ROLE_CHOICES_DOCTOR)
     return worker
 
 
@@ -255,7 +262,8 @@ def create_voucher_partner():
         unit="LCSB",
         phone_number="0123456789"
     )
-    WorkerStudyRole.objects.create(worker=worker, study_id=GLOBAL_STUDY_ID, role=WORKER_VOUCHER_PARTNER)
+    WorkerStudyRole.objects.create(
+        worker=worker, study_id=GLOBAL_STUDY_ID, role=WORKER_VOUCHER_PARTNER)
     return worker
 
 
@@ -349,10 +357,12 @@ def format_form_field(value):
 def prepare_test_redcap_connection():
     Language.objects.create(name="Finnish").save()
     Language.objects.create(name="Italian").save()
-    token_item = ConfigurationItem.objects.filter(type=REDCAP_TOKEN_CONFIGURATION_TYPE)[0]
+    token_item = ConfigurationItem.objects.filter(
+        type=REDCAP_TOKEN_CONFIGURATION_TYPE)[0]
     # noinspection SpellCheckingInspection
     token_item.value = "5C75EEC3DBDDA5218B6ACC0424B3F695"
     token_item.save()
-    url_item = ConfigurationItem.objects.filter(type=REDCAP_BASE_URL_CONFIGURATION_TYPE)[0]
+    url_item = ConfigurationItem.objects.filter(
+        type=REDCAP_BASE_URL_CONFIGURATION_TYPE)[0]
     url_item.value = "https://luxparktest.org/redcap/"
     url_item.save()
diff --git a/smash/web/tests/models/test_study.py b/smash/web/tests/models/test_study.py
index 9c9e02f77c08015bd59a4ef19149945caa5a0e6b..c535aa57a01becec96c39fb51ef4da443105de5a 100644
--- a/smash/web/tests/models/test_study.py
+++ b/smash/web/tests/models/test_study.py
@@ -1,14 +1,22 @@
 import logging
 
 from django.test import TestCase
-
-from web.tests.functions import create_study
+from django.forms import ValidationError
+from web.tests.functions import create_study, create_study_subject
+from web.forms.study_forms import StudyEditForm
+from web.models.study import Study
+from web.models.study_subject import StudySubject
 
 logger = logging.getLogger(__name__)
 
 
 class StudyTests(TestCase):
+
     def test_image_img(self):
         study = create_study()
-
         self.assertTrue(study.name in str(study))
+
+    def test_check_nd_number(self):
+        study = create_study()
+        # check the default regex
+        self.assertTrue(study.check_nd_number('ND0001'))
diff --git a/smash/web/tests/models/test_study_subject.py b/smash/web/tests/models/test_study_subject.py
index b70add8cee109783433fdba1e5056bf60b1235cd..f91762f35e0df2c664e7b69b00f0cb40dd45192d 100644
--- a/smash/web/tests/models/test_study_subject.py
+++ b/smash/web/tests/models/test_study_subject.py
@@ -2,41 +2,73 @@ from django.test import TestCase
 
 from web.models import Appointment
 from web.models import Visit
+from web.models import StudySubject, Study
 from web.tests.functions import create_study_subject, create_appointment, create_study_subject_with_multiple_screening_numbers
 from web.tests.functions import create_visit
 
 
 class SubjectModelTests(TestCase):
+
     def test_mark_as_resigned(self):
         subject = create_study_subject()
         visit = create_visit(subject)
         appointment = create_appointment(visit)
 
         subject.mark_as_resigned()
-        appointment_status = Appointment.objects.filter(id=appointment.id)[0].status
+        appointment_status = Appointment.objects.filter(id=appointment.id)[
+            0].status
         visit_finished = Visit.objects.filter(id=visit.id)[0].is_finished
 
         self.assertTrue(subject.resigned)
         self.assertTrue(visit_finished)
-        self.assertEquals(Appointment.APPOINTMENT_STATUS_CANCELLED, appointment_status)
+        self.assertEquals(
+            Appointment.APPOINTMENT_STATUS_CANCELLED, appointment_status)
+
+    def test_check_nd_number_regex(self):
+        # delete everything
+        StudySubject.objects.all().delete()
+        # get default regex
+        nd_number_study_subject_regex_default = Study._meta.get_field(
+            'nd_number_study_subject_regex').get_default()
+        self.assertTrue(StudySubject.check_nd_number_regex(
+            nd_number_study_subject_regex_default))
+        # this will add a studysubject with a NDnumber
+        study_subject = create_study_subject(nd_number='ND0001')
+
+        self.assertTrue(StudySubject.check_nd_number_regex(
+            nd_number_study_subject_regex_default))
+        # delete everything
+        StudySubject.objects.all().delete()
+        # this will add a studysubject with a NDnumber
+        create_study_subject(nd_number='ND00001')
+        self.assertFalse(StudySubject.check_nd_number_regex(
+            nd_number_study_subject_regex_default))
 
     def test_sort_matched_screening_first(self):
 
         def create_result(phrase, subject_id=1):
             phrase = phrase.format(subject_id=subject_id)
             phrase = phrase.split(';')
-            for i,r in enumerate(phrase):
+            for i, r in enumerate(phrase):
                 letter, num = phrase[i].strip().split('-')
                 phrase[i] = (letter, int(num))
             return phrase
 
-        subject = create_study_subject_with_multiple_screening_numbers(subject_id=1)
-        self.assertEqual(subject.sort_matched_screening_first('L'), create_result('L-00{subject_id}; E-00{subject_id}', subject_id=1))
-        self.assertEqual(subject.sort_matched_screening_first('L-00'), create_result('L-00{subject_id}; E-00{subject_id}', subject_id=1))
-        self.assertEqual(subject.sort_matched_screening_first('E'), create_result('E-00{subject_id}; L-00{subject_id}', subject_id=1))
-        self.assertEqual(subject.sort_matched_screening_first('-'), create_result('E-00{subject_id}; L-00{subject_id}', subject_id=1))
-        self.assertEqual(subject.sort_matched_screening_first(''), create_result('E-00{subject_id}; L-00{subject_id}', subject_id=1))
-        self.assertEqual(subject.sort_matched_screening_first('001'), create_result('E-00{subject_id}; L-00{subject_id}', subject_id=1))
-        self.assertEqual(subject.sort_matched_screening_first('00'), create_result('E-00{subject_id}; L-00{subject_id}', subject_id=1))
-        self.assertEqual(subject.sort_matched_screening_first('potato'), create_result('E-00{subject_id}; L-00{subject_id}', subject_id=1))
-        
\ No newline at end of file
+        subject = create_study_subject_with_multiple_screening_numbers(
+            subject_id=1)
+        self.assertEqual(subject.sort_matched_screening_first('L'), create_result(
+            'L-00{subject_id}; E-00{subject_id}', subject_id=1))
+        self.assertEqual(subject.sort_matched_screening_first(
+            'L-00'), create_result('L-00{subject_id}; E-00{subject_id}', subject_id=1))
+        self.assertEqual(subject.sort_matched_screening_first('E'), create_result(
+            'E-00{subject_id}; L-00{subject_id}', subject_id=1))
+        self.assertEqual(subject.sort_matched_screening_first(
+            '-'), create_result('E-00{subject_id}; L-00{subject_id}', subject_id=1))
+        self.assertEqual(subject.sort_matched_screening_first(''), create_result(
+            'E-00{subject_id}; L-00{subject_id}', subject_id=1))
+        self.assertEqual(subject.sort_matched_screening_first('001'), create_result(
+            'E-00{subject_id}; L-00{subject_id}', subject_id=1))
+        self.assertEqual(subject.sort_matched_screening_first('00'), create_result(
+            'E-00{subject_id}; L-00{subject_id}', subject_id=1))
+        self.assertEqual(subject.sort_matched_screening_first('potato'), create_result(
+            'E-00{subject_id}; L-00{subject_id}', subject_id=1))
diff --git a/smash/web/tests/view/test_appointments.py b/smash/web/tests/view/test_appointments.py
index a1544f213bdcfcb70a699f4b9299c61faa5b069d..8f24b3396fb8f2677b3547e065105cb54e3d6a64 100644
--- a/smash/web/tests/view/test_appointments.py
+++ b/smash/web/tests/view/test_appointments.py
@@ -102,7 +102,7 @@ class AppointmentsViewTests(LoggedInTestCase):
         self.assertEqual(Appointment.APPOINTMENT_STATUS_FINISHED, appointment_result.status)
 
     def test_save_appointments_edit_with_invalid_nd_number(self):
-        subject = create_study_subject()
+        subject = create_study_subject(nd_number=None)
         visit = create_visit(subject)
         appointment = create_appointment(visit, get_today_midnight_date())
 
diff --git a/smash/web/views/appointment.py b/smash/web/views/appointment.py
index c4a9ddf1f5a37259e369de156f44b5ea6031d564..ee45e0d173bc980f05d866df56cb70387ae05830 100644
--- a/smash/web/views/appointment.py
+++ b/smash/web/views/appointment.py
@@ -1,17 +1,18 @@
 # coding=utf-8
 import logging
 import re
-
+import datetime
 from django.contrib import messages
 from django.core.exceptions import ValidationError
 from django.shortcuts import get_object_or_404, redirect
 
+from web.models.constants import GLOBAL_STUDY_ID
 from web.models.appointment_list import APPOINTMENT_LIST_APPROACHING, APPOINTMENT_LIST_GENERIC, \
     APPOINTMENT_LIST_UNFINISHED
 from . import wrap_response
 from web.forms import AppointmentDetailForm, AppointmentEditForm, AppointmentAddForm, SubjectEditForm, \
     StudySubjectEditForm
-from ..models import Appointment, StudySubject, MailTemplate
+from ..models import Appointment, StudySubject, MailTemplate, Visit, Study
 
 logger = logging.getLogger(__name__)
 
@@ -40,6 +41,13 @@ def appointment_details(request, id):
 
 
 def appointment_add(request, visit_id=None):
+    if visit_id is not None:
+        visit  = get_object_or_404(Visit, id=visit_id)
+        visit_start = visit.datetime_begin.strftime("%Y-%m-%d")
+        visit_end   = visit.datetime_end.strftime("%Y-%m-%d")
+    else:
+        visit_start = datetime.datetime.today().strftime("%Y-%m-%d")
+        visit_end   = datetime.datetime.today().strftime("%Y-%m-%d")
     if request.method == 'POST':
         form = AppointmentAddForm(request.POST, request.FILES, user=request.user)
         if form.is_valid():
@@ -49,11 +57,16 @@ def appointment_add(request, visit_id=None):
                 return redirect('web.views.appointments')
             else:
                 return redirect('web.views.visit_details', id=visit_id)
+        else:
+            raise ValidationError("Invalid request: Errors: {}. Non field errors: {}".format(form.errors, form.non_field_errors()))
+
     else:
         form = AppointmentAddForm(user=request.user)
 
     return wrap_response(request, 'appointments/add.html',
-                         {'form': form, 'visitID': visit_id, 'full_list': APPOINTMENT_LIST_GENERIC})
+                         {'form': form, 'visitID': visit_id, 'isGeneral': visit_id is None, 
+                         'visit_start': visit_start, 'visit_end': visit_end, 
+                         'full_list': APPOINTMENT_LIST_GENERIC})
 
 
 def appointment_edit(request, id):
@@ -61,6 +74,7 @@ def appointment_edit(request, id):
     study_subject_form = None
     subject_form = None
     contact_attempts = None
+    study = Study.get_by_id(GLOBAL_STUDY_ID)
 
     if request.method == 'POST':
         appointment_form = AppointmentEditForm(request.POST,
@@ -89,7 +103,7 @@ def appointment_edit(request, id):
                                                status=Appointment.APPOINTMENT_STATUS_FINISHED).count() == 0:
                 adjust_date = True
             if appointment_form.cleaned_data["status"] == Appointment.APPOINTMENT_STATUS_FINISHED:
-                if re.match('ND[0-9][0-9][0-9][0-9]', study_subject_form.cleaned_data["nd_number"]) is None:
+                if not study.check_nd_number(study_subject_form.cleaned_data["nd_number"]):
                     study_subject_form.add_error('nd_number', ValidationError("invalid ND number"))
                     is_valid_form = False
         if is_valid_form: