diff --git a/smash/web/migrations/0101_auto_20171214_1047.py b/smash/web/migrations/0101_auto_20171214_1047.py new file mode 100644 index 0000000000000000000000000000000000000000..26e3d5740cd5870018d7613e684fe46c0f8fdc61 --- /dev/null +++ b/smash/web/migrations/0101_auto_20171214_1047.py @@ -0,0 +1,25 @@ +# -*- coding: utf-8 -*- +# Generated by Django 1.10.7 on 2017-12-14 10:47 +from __future__ import unicode_literals + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('web', '0100_auto_20171213_1140'), + ] + + operations = [ + migrations.AddField( + model_name='study', + name='auto_create_follow_up', + field=models.BooleanField(default=True, verbose_name=b'Auto create follow up visit'), + ), + migrations.AlterField( + model_name='worker', + name='email', + field=models.EmailField(blank=True, max_length=254, verbose_name=b'E-mail'), + ), + ] diff --git a/smash/web/models/study.py b/smash/web/models/study.py index 04a8e68e01cc32d1d6b5e12be22112e720137793..4501a3be57d712de4cb3f35cf77eae8a9407c67a 100644 --- a/smash/web/models/study.py +++ b/smash/web/models/study.py @@ -19,6 +19,11 @@ class Study(models.Model): on_delete=models.CASCADE, ) + auto_create_follow_up = models.BooleanField( + default=True, + verbose_name="Auto create follow up visit" + ) + def __str__(self): return "%s" % self.name diff --git a/smash/web/models/visit.py b/smash/web/models/visit.py index 2922ea8bb66ba4e71fd213edd5ff660be87f9304..f94d30ddbe876ba539a415f887e62c4848a3d474 100644 --- a/smash/web/models/visit.py +++ b/smash/web/models/visit.py @@ -51,7 +51,15 @@ class Visit(models.Model): self.is_finished = True self.save() - if (not self.subject.subject.dead) and (not self.subject.resigned): + create_follow_up = True + if self.subject.subject.dead: + create_follow_up = False + elif self.subject.resigned: + create_follow_up = False + elif not self.subject.study.auto_create_follow_up: + create_follow_up = False + + if create_follow_up: visit_started = Visit.objects.filter(subject=self.subject).filter(visit_number=1)[0].datetime_begin follow_up_number = Visit.objects.filter(subject=self.subject).count() + 1 diff --git a/smash/web/tests/view/test_notifications.py b/smash/web/tests/view/test_notifications.py index e84952c33c2207af6c1c65c0e505da4768e0d876..1be70d94ce1c722e4c45f68a55de6aecb2eb8605 100644 --- a/smash/web/tests/view/test_notifications.py +++ b/smash/web/tests/view/test_notifications.py @@ -4,10 +4,10 @@ import logging from django.contrib.auth.models import AnonymousUser from web.models import Appointment, Location, AppointmentTypeLink, Study, Visit -from web.models.constants import GLOBAL_STUDY_ID +from web.models.constants import GLOBAL_STUDY_ID, VOUCHER_STATUS_USED from web.tests import LoggedInTestCase from web.tests.functions import create_appointment, create_location, create_worker, create_appointment_type, \ - create_empty_notification_parameters, create_study_subject, create_visit + create_empty_notification_parameters, create_study_subject, create_visit, create_voucher from web.views.notifications import \ get_approaching_visits_for_mail_contact, \ get_approaching_visits_for_mail_contact_count, \ @@ -236,6 +236,24 @@ class NotificationViewTests(LoggedInTestCase): notification = get_subject_with_no_visit_notifications_count(self.user) self.assertEquals(original_notification.count + 1, notification.count) + def test_get_subject_with_no_visit_notifications_count_with_new_voucher(self): + original_notification = get_subject_with_no_visit_notifications_count(self.user) + study_subject = create_study_subject() + create_voucher(study_subject) + + notification = get_subject_with_no_visit_notifications_count(self.user) + self.assertEquals(original_notification.count, notification.count) + + def test_get_subject_with_no_visit_notifications_count_with_used_voucher(self): + original_notification = get_subject_with_no_visit_notifications_count(self.user) + study_subject = create_study_subject() + voucher = create_voucher(study_subject) + voucher.status = VOUCHER_STATUS_USED + voucher.save() + + notification = get_subject_with_no_visit_notifications_count(self.user) + self.assertEquals(original_notification.count + 1, notification.count) + def test_get_subject_with_no_visit_notifications_count_2(self): original_notification = get_subject_with_no_visit_notifications_count(self.user) subject = create_study_subject() diff --git a/smash/web/tests/view/test_visit.py b/smash/web/tests/view/test_visit.py index 5f430b4b07f5a09915c4f42a66c3b29667accd80..549afd5e2f4de3fd72e56824310a49c55d26fe39 100644 --- a/smash/web/tests/view/test_visit.py +++ b/smash/web/tests/view/test_visit.py @@ -3,12 +3,12 @@ import logging from django.urls import reverse -from web.forms import VisitDetailForm, VisitAddForm +from web.forms import VisitDetailForm from web.models import Visit, MailTemplate from web.models.constants import MAIL_TEMPLATE_CONTEXT_VISIT from web.tests import LoggedInTestCase from web.tests.functions import create_study_subject, create_visit, create_appointment, create_appointment_type, \ - create_language, get_resource_path + create_language, get_resource_path, format_form_field from web.views.notifications import get_today_midnight_date logger = logging.getLogger(__name__) @@ -43,11 +43,7 @@ class VisitViewTests(LoggedInTestCase): visit_detail_form = VisitDetailForm(instance=visit) form_data = {} for key, value in visit_detail_form.initial.items(): - if value is not None: - if isinstance(value, datetime.datetime): - form_data[key] = value.strftime("%Y-%m-%d") - else: - form_data[key] = value + form_data[key] = format_form_field(value) return form_data def test_render_visit_details_with_mail_templates(self): @@ -78,14 +74,7 @@ class VisitViewTests(LoggedInTestCase): visit_count = Visit.objects.all().count() subject = create_study_subject() - form = VisitAddForm() - form_data = {} - for key, value in form.initial.items(): - if value is not None: - if isinstance(value, datetime.datetime): - form_data[key] = value.strftime("%Y-%m-%d") - else: - form_data[key] = value + form_data = self.create_visit_detail_form_data(None) form_data["datetime_begin"] = "2017-01-01" form_data["datetime_end"] = "2017-04-01" @@ -109,6 +98,22 @@ class VisitViewTests(LoggedInTestCase): new_visit = Visit.objects.get(id=visit.id) self.assertTrue(new_visit.is_finished) + self.assertEqual(2, Visit.objects.count()) + + def test_mark_as_finished_with_study_no_follow_up_rule(self): + visit = create_visit() + study = visit.subject.study + study.auto_create_follow_up = False + study.save() + + self.assertFalse(visit.is_finished) + + response = self.client.get(reverse('web.views.visit_mark', args=[visit.id, "finished"])) + self.assertEqual(response.status_code, 302) + + new_visit = Visit.objects.get(id=visit.id) + self.assertTrue(new_visit.is_finished) + self.assertEqual(1, Visit.objects.count()) def test_visit_list(self): create_visit() diff --git a/smash/web/views/notifications.py b/smash/web/views/notifications.py index 2ef58548948192fb1b4fb4d606858c8eba81a85c..5a42783a6a7233b6b0fcf22b66ec0f8e083301a2 100644 --- a/smash/web/views/notifications.py +++ b/smash/web/views/notifications.py @@ -6,7 +6,7 @@ from django.db.models import Count, Case, When, Q, F from django.utils import timezone from web.models import Study -from web.models.constants import GLOBAL_STUDY_ID +from web.models.constants import GLOBAL_STUDY_ID, VOUCHER_STATUS_NEW from ..models import Worker, StudySubject, Visit, Appointment, Location, MissingSubject, InconsistentSubject @@ -145,14 +145,15 @@ def get_notifications(the_user): def get_subjects_with_no_visit(user): - result = StudySubject.objects.annotate(my_count=Count(Case(When(visit__is_finished=False, then=1)))).filter( + result = StudySubject.objects.annotate( + unfinished_visit_count=Count(Case(When(visit__is_finished=False, then=1)))).filter( subject__dead=False, resigned=False, - my_count=0, + unfinished_visit_count=0, default_location__in=get_filter_locations(user), postponed=False, datetime_contact_reminder__isnull=True, - ) + ).exclude(vouchers__status=VOUCHER_STATUS_NEW) return result @@ -242,13 +243,14 @@ def waiting_for_appointment(visit): required_types = visit.appointment_types.all() appointment_types = [] for appointment in visit.appointment_set.all(): - for type in appointment.appointment_types.all(): + for appointment_type in appointment.appointment_types.all(): if (appointment.status in [Appointment.APPOINTMENT_STATUS_FINISHED, - Appointment.APPOINTMENT_STATUS_SCHEDULED]) and (not (type in appointment_types)): - appointment_types.append(type) + Appointment.APPOINTMENT_STATUS_SCHEDULED]) and ( + not (appointment_type in appointment_types)): + appointment_types.append(appointment_type) result = False - for type in required_types: - if not (type in appointment_types): + for appointment_type in required_types: + if not (appointment_type in appointment_types): result = True return result @@ -266,8 +268,9 @@ def get_active_visits_without_appointments(user): # performed types_in_system_count=Count(Case(When( Q(appointment__status=Appointment.APPOINTMENT_STATUS_SCHEDULED) | - Q(appointment__status=Appointment.APPOINTMENT_STATUS_FINISHED) - , then="appointment__appointment_types")), distinct=True)).annotate( + Q(appointment__status=Appointment.APPOINTMENT_STATUS_FINISHED), + then="appointment__appointment_types")), + distinct=True)).annotate( # types_expected_in_system_count annotation counts how many different appointment types should be performed in # the visit types_expected_in_system_count=Count('appointment_types', distinct=True))