diff --git a/smash/web/api_views/subject.py b/smash/web/api_views/subject.py
index 170367b0a5999c0cd91a42329efd0b83f08cf6ab..946b45b25de13468f0322604072b172b1fa9581a 100644
--- a/smash/web/api_views/subject.py
+++ b/smash/web/api_views/subject.py
@@ -1,11 +1,11 @@
 import logging
 
 from django.contrib.auth.decorators import login_required
-from django.db.models import Count, Case, When, Min
+from django.db.models import Count, Case, When, Min, Max
 from django.db.models import Q
 from django.http import JsonResponse
 
-from web.models import StudySubject, Visit, Appointment, Subject, SubjectColumns, StudyColumns, Study
+from web.models import StudySubject, Visit, Appointment, Subject, SubjectColumns, StudyColumns, Study, ContactAttempt
 from web.models.constants import SUBJECT_TYPE_CHOICES, GLOBAL_STUDY_ID
 from web.models.study_subject_list import SUBJECT_LIST_GENERIC, SUBJECT_LIST_NO_VISIT, SUBJECT_LIST_REQUIRE_CONTACT, \
     StudySubjectList
@@ -51,11 +51,13 @@ def add_column(result, name, field_name, column_list, param, columns_used_in_stu
 @login_required
 def get_subject_columns(request, subject_list_type):
     study = Study.objects.filter(id=GLOBAL_STUDY_ID)[0]
-    study_subject_list = StudySubjectList.objects.filter(study=study, type=subject_list_type)
-    if len(study_subject_list) > 0:
-        subject_columns = study_subject_list[0].visible_subject_columns
-        study_subject_columns = study_subject_list[0].visible_subject_study_columns
+    study_subject_lists = StudySubjectList.objects.filter(study=study, type=subject_list_type)
+    if len(study_subject_lists) > 0:
+        study_subject_list = study_subject_lists[0]
+        subject_columns = study_subject_list.visible_subject_columns
+        study_subject_columns = study_subject_list.visible_subject_study_columns
     else:
+        study_subject_list = StudySubjectList()
         subject_columns = SubjectColumns()
         study_subject_columns = StudyColumns()
 
@@ -65,6 +67,8 @@ def get_subject_columns(request, subject_list_type):
     add_column(result, "First name", "first_name", subject_columns, "string_filter")
     add_column(result, "Last name", "last_name", subject_columns, "string_filter")
     add_column(result, "Date of birth", "date_born", subject_columns, None)
+    add_column(result, "Contact on", "datetime_contact_reminder", study_subject_columns, None)
+    add_column(result, "Last contact attempt", "last_contact_attempt", study_subject_list, None)
     add_column(result, "Location", "default_location", study_subject_columns, "location_filter", study.columns)
     add_column(result, "Deceased", "dead", subject_columns, "yes_no_filter")
     add_column(result, "Resigned", "resigned", study_subject_columns, "yes_no_filter", study.columns)
@@ -132,6 +136,12 @@ def get_subjects_order(subjects_to_be_ordered, order_column, order_direction):
         result = subjects_to_be_ordered.order_by(order_direction + 'id')
     elif order_column == "date_born":
         result = subjects_to_be_ordered.order_by(order_direction + 'subject__date_born')
+    elif order_column == "datetime_contact_reminder":
+        result = subjects_to_be_ordered.order_by(order_direction + 'datetime_contact_reminder')
+    elif order_column == "last_contact_attempt":
+        # noinspection SpellCheckingInspection
+        result = subjects_to_be_ordered.annotate(sort_contact_attempt=Max("contactattempt__datetime_when")).order_by(
+            order_direction + 'sort_contact_attempt')
     elif str(order_column).startswith("visit_"):
         visit_number = get_visit_number_from_visit_x_string(order_column)
         result = order_by_visit(subjects_to_be_ordered, order_direction, visit_number)
@@ -340,11 +350,24 @@ def serialize_subject(study_subject):
             "datetime_start": visit.datetime_begin.strftime('%Y-%m-%d'),
             "datetime_end": visit.datetime_end.strftime('%Y-%m-%d'),
         })
+    contact_reminder = study_subject.datetime_contact_reminder
+    if contact_reminder is not None:
+        contact_reminder = contact_reminder.strftime('%Y-%m-%d %H:%M')
+    contact_attempts = ContactAttempt.objects.filter(subject=study_subject).order_by("-datetime_when")
+    if len(contact_attempts) > 0:
+        last_contact_attempt = contact_attempts[0]
+        last_contact_attempt_string = last_contact_attempt.datetime_when.strftime(
+            '%Y-%m-%d %H:%M') + "<br/>" + str(last_contact_attempt.worker) + "<br/> Success: " + get_yes_no(
+            last_contact_attempt.success) + "<br/>" + last_contact_attempt.comment
 
+    else:
+        last_contact_attempt_string = ""
     result = {
         "first_name": study_subject.subject.first_name,
         "last_name": study_subject.subject.last_name,
         "date_born": study_subject.subject.date_born,
+        "datetime_contact_reminder": contact_reminder,
+        "last_contact_attempt": last_contact_attempt_string,
         "nd_number": study_subject.nd_number,
         "screening_number": study_subject.screening_number,
         "default_location": location,
diff --git a/smash/web/migrations/0080_auto_20171204_1341.py b/smash/web/migrations/0080_auto_20171204_1341.py
new file mode 100644
index 0000000000000000000000000000000000000000..e513330345951900260658d4cd4940c0005d2bed
--- /dev/null
+++ b/smash/web/migrations/0080_auto_20171204_1341.py
@@ -0,0 +1,80 @@
+# -*- coding: utf-8 -*-
+# Generated by Django 1.10.7 on 2017-12-04 13:41
+from __future__ import unicode_literals
+
+from django.db import migrations, models
+
+
+# noinspection PyUnusedLocal
+# noinspection PyPep8Naming
+def create_default_columns_for_SUBJECT_LIST_REQUIRE_CONTACT(apps, schema_editor):
+    # We can't import the Study model directly as it may be a newer
+    # version than this migration expects. We use the historical version.
+    SubjectColumns = apps.get_model("web", "SubjectColumns")
+    subject_columns = SubjectColumns.objects.create()
+    subject_columns.sex = False
+    subject_columns.first_name = True
+    subject_columns.last_name = True
+    subject_columns.languages = False
+    subject_columns.default_written_communication_language = True
+    subject_columns.phone_number = False
+    subject_columns.phone_number_2 = False
+    subject_columns.phone_number_3 = False
+    subject_columns.email = False
+    subject_columns.date_born = False
+    subject_columns.address = False
+    subject_columns.postal_code = False
+    subject_columns.city = False
+    subject_columns.country = False
+    subject_columns.dead = False
+    subject_columns.save()
+
+    StudyColumns = apps.get_model("web", "StudyColumns")
+    study_columns = StudyColumns.objects.create()
+    study_columns.postponed = False
+    study_columns.datetime_contact_reminder = True
+    study_columns.type = False
+    study_columns.default_location = False
+    study_columns.flying_team = False
+    study_columns.screening_number = False
+    study_columns.nd_number = False
+    study_columns.mpower_id = False
+    study_columns.comments = False
+    study_columns.referral = False
+    study_columns.diagnosis = False
+    study_columns.year_of_diagnosis = False
+    study_columns.information_sent = False
+    study_columns.pd_in_family = False
+    study_columns.resigned = False
+    study_columns.resign_reason = False
+    study_columns.save()
+
+
+class Migration(migrations.Migration):
+    dependencies = [
+        ('web', '0079_auto_20171204_1235'),
+    ]
+
+    operations = [
+        migrations.AlterField(
+            model_name='studycolumns',
+            name='datetime_contact_reminder',
+            field=models.BooleanField(choices=[(True, b'Yes'), (False, b'No')], default=True,
+                                      verbose_name=b'Last contact attempt'),
+        ),
+        migrations.RunSQL('UPDATE web_studycolumns SET datetime_contact_reminder =FALSE WHERE ' +
+                          'NOT(id IN (SELECT columns_id FROM web_study));'),
+
+        migrations.RunPython(create_default_columns_for_SUBJECT_LIST_REQUIRE_CONTACT),
+
+        migrations.RunSQL('INSERT INTO web_studysubjectlist (' +
+                          'study_id, ' +
+                          'visible_subject_study_columns_id, ' +
+                          'visible_subject_columns_id, ' +
+                          'type) ' +
+                          "SELECT " +
+                          "1, " +
+                          "max(web_studycolumns.id), " +
+                          "max(web_subjectcolumns.id), " +
+                          "'REQUIRE_CONTACT' FROM web_studycolumns, web_subjectcolumns;"),
+    ]
diff --git a/smash/web/migrations/0081_studysubjectlist_last_contact_attempt.py b/smash/web/migrations/0081_studysubjectlist_last_contact_attempt.py
new file mode 100644
index 0000000000000000000000000000000000000000..571ce6737560d8d0f74f5689d790ff29202f8867
--- /dev/null
+++ b/smash/web/migrations/0081_studysubjectlist_last_contact_attempt.py
@@ -0,0 +1,20 @@
+# -*- coding: utf-8 -*-
+# Generated by Django 1.10.7 on 2017-12-04 14:31
+from __future__ import unicode_literals
+
+from django.db import migrations, models
+
+
+class Migration(migrations.Migration):
+    dependencies = [
+        ('web', '0080_auto_20171204_1341'),
+    ]
+
+    operations = [
+        migrations.AddField(
+            model_name='studysubjectlist',
+            name='last_contact_attempt',
+            field=models.BooleanField(default=False, verbose_name=b'Last contact attempt'),
+        ),
+        migrations.RunSQL("UPDATE web_studysubjectlist SET last_contact_attempt=TRUE WHERE type='REQUIRE_CONTACT'"),
+    ]
diff --git a/smash/web/models/study_columns.py b/smash/web/models/study_columns.py
index 15142bd56913678159e4d92ef53928d0f7440ad0..7700a61be37532167f324d701fd8c771d9aecbe1 100644
--- a/smash/web/models/study_columns.py
+++ b/smash/web/models/study_columns.py
@@ -77,3 +77,8 @@ class StudyColumns(models.Model):
                                         default=True,
                                         verbose_name='Resign reason'
                                         )
+
+    datetime_contact_reminder = models.BooleanField(choices=BOOL_CHOICES,
+                                                    default=True,
+                                                    verbose_name='Last contact attempt'
+                                                    )
diff --git a/smash/web/models/study_subject_list.py b/smash/web/models/study_subject_list.py
index fae16c14fb03cecdcae5d75adaffcf746c217513..887f7719e46aa3b7951909693ddbbf3465e89840 100644
--- a/smash/web/models/study_subject_list.py
+++ b/smash/web/models/study_subject_list.py
@@ -36,6 +36,11 @@ class StudySubjectList(models.Model):
         null=False,
     )
 
+    last_contact_attempt = models.BooleanField(
+        default=False,
+        verbose_name='Last contact attempt'
+    )
+
     type = models.CharField(max_length=50,
                             choices=SUBJECT_LIST_CHOICES.items(),
                             verbose_name='Type o list',
diff --git a/smash/web/tests/api_views/test_subject.py b/smash/web/tests/api_views/test_subject.py
index 7dc320a195db39709542773cd26735e09dfc0cdd..71f3adc756e5c49e2cd25ceba76ad23e3aacdc78 100644
--- a/smash/web/tests/api_views/test_subject.py
+++ b/smash/web/tests/api_views/test_subject.py
@@ -14,7 +14,7 @@ from web.models.constants import GLOBAL_STUDY_ID
 from web.models.study_subject_list import SUBJECT_LIST_GENERIC, SUBJECT_LIST_NO_VISIT, SUBJECT_LIST_REQUIRE_CONTACT, \
     StudySubjectList
 from web.tests.functions import create_study_subject, create_worker, create_get_suffix, create_visit, \
-    create_appointment, create_empty_study_columns
+    create_appointment, create_empty_study_columns, create_contact_attempt
 from web.views.notifications import get_today_midnight_date
 
 logger = logging.getLogger(__name__)
@@ -57,6 +57,18 @@ class TestApi(TestCase):
         columns = json.loads(response.content)['columns']
         self.assertTrue(len(columns) >= 20)
 
+    def test_get_columns_for_require_contact(self):
+        response = self.client.get(
+            reverse('web.api.subjects.columns', kwargs={'subject_list_type': SUBJECT_LIST_REQUIRE_CONTACT}))
+        self.assertEqual(response.status_code, 200)
+
+        columns = json.loads(response.content)['columns']
+        visible_columns = 0
+        for column in columns:
+            if column["visible"]:
+                visible_columns += 1
+        self.assertTrue(visible_columns < 20)
+
     def test_get_columns_when_no_list_is_available(self):
         StudySubjectList.objects.all().delete()
         response = self.client.get(
@@ -179,6 +191,17 @@ class TestApi(TestCase):
 
         self.check_subject_ordered("date_born", [subject, subject2])
 
+    def test_subjects_sort_contact_on(self):
+        subject = self.study_subject
+        subject.datetime_contact_reminder = get_today_midnight_date()
+        subject.save()
+
+        subject2 = create_study_subject(2)
+        subject2.datetime_contact_reminder = get_today_midnight_date() + datetime.timedelta(days=1)
+        subject2.save()
+
+        self.check_subject_ordered("datetime_contact_reminder", [subject, subject2])
+
     def test_subjects_sort_default_location(self):
         subject = self.study_subject
 
@@ -323,6 +346,8 @@ class TestApi(TestCase):
     def test_serialize_subject(self):
         study_subject = self.study_subject
         study_subject.subject.dead = True
+        create_contact_attempt(subject=study_subject)
+        create_visit(subject=study_subject)
 
         subject_json = serialize_subject(study_subject)
         self.assertEqual("YES", subject_json["dead"])
@@ -456,3 +481,11 @@ class TestApi(TestCase):
 
     def test_invalid_order(self):
         self.check_subject_ordered(None, [self.study_subject])
+
+    def test_subjects_ordered_by_contact_attempt(self):
+        subject = self.study_subject
+        subject2 = create_study_subject(2)
+
+        create_contact_attempt(subject=subject)
+
+        self.check_subject_ordered("last_contact_attempt", [subject, subject2])