diff --git a/smash/web/migrations/0133_auto_20181113_1550.py b/smash/web/migrations/0133_auto_20181113_1550.py new file mode 100644 index 0000000000000000000000000000000000000000..efc19768b94521fcc1c12fcdaf030d640d94a8f7 --- /dev/null +++ b/smash/web/migrations/0133_auto_20181113_1550.py @@ -0,0 +1,41 @@ +# -*- coding: utf-8 -*- +# Generated by Django 1.11.5 on 2018-11-13 15:50 +from __future__ import unicode_literals + +import django.core.validators +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('web', '0132_study_default_visit_duration_in_months'), + ] + + operations = [ + migrations.AddField( + model_name='study', + name='default_delta_time_for_control_follow_up', + field=models.IntegerField(default=4, help_text=b'Time difference between visits used to automatically create follow up visits', validators=[django.core.validators.MinValueValidator(1)], verbose_name=b'Time difference between control visits'), + ), + migrations.AddField( + model_name='study', + name='default_delta_time_for_follow_up_units', + field=models.CharField(choices=[(b'days', b'Days'), (b'years', b'Years')], default=b'years', help_text=b'Units for the number of days between visits for both patients and controls', max_length=10, verbose_name=b'Units for the follow up incrementals'), + ), + migrations.AddField( + model_name='study', + name='default_delta_time_for_patient_follow_up', + field=models.IntegerField(default=1, help_text=b'Time difference between visits used to automatically create follow up visits', validators=[django.core.validators.MinValueValidator(1)], verbose_name=b'Time difference between patient visits'), + ), + migrations.AlterField( + model_name='study', + name='default_visit_duration_in_months', + field=models.IntegerField(default=6, help_text=b'Duration of the visit, this is, the time interval, in months, when the appointments may take place', validators=[django.core.validators.MinValueValidator(1)], verbose_name=b'Duration of the visits in months'), + ), + migrations.AlterField( + model_name='study', + name='default_voucher_expiration_in_months', + field=models.IntegerField(default=3, validators=[django.core.validators.MinValueValidator(1)], verbose_name=b'Duration of the vouchers in months'), + ), + ] diff --git a/smash/web/models/study.py b/smash/web/models/study.py index 5b9d0a740ca08cdfc620377d23ed6975b6474074..b4e9dfa5a1410cfd82d4a6b2d42a915cb9f81f57 100644 --- a/smash/web/models/study.py +++ b/smash/web/models/study.py @@ -6,6 +6,12 @@ from django.core.validators import MaxValueValidator, MinValueValidator import re +FOLLOW_UP_INCREMENT_IN_YEARS = 'years' +FOLLOW_UP_INCREMENT_IN_DAYS = 'days' +FOLLOW_UP_INCREMENT_UNIT_CHOICE = { + FOLLOW_UP_INCREMENT_IN_YEARS: 'Years', + FOLLOW_UP_INCREMENT_IN_DAYS: 'Days' +} class Study(models.Model): @@ -39,17 +45,40 @@ class Study(models.Model): ) default_voucher_expiration_in_months = models.IntegerField( - verbose_name='Default duration of the vouchers in months', + verbose_name='Duration of the vouchers in months', default=3, validators=[MinValueValidator(1)] ) default_visit_duration_in_months = models.IntegerField( - verbose_name='Default duration of the visits in months', - default=3, + verbose_name='Duration of the visits in months', + help_text='Duration of the visit, this is, the time interval, in months, when the appointments may take place', + default=6, validators=[MinValueValidator(1)] ) + default_delta_time_for_patient_follow_up = models.IntegerField( + verbose_name='Time difference between patient visits', + help_text='Time difference between visits used to automatically create follow up visits', + default=1, + validators=[MinValueValidator(1)] + ) + + default_delta_time_for_control_follow_up = models.IntegerField( + verbose_name='Time difference between control visits', + help_text='Time difference between visits used to automatically create follow up visits', + default=4, + validators=[MinValueValidator(1)] + ) + + default_delta_time_for_follow_up_units = models.CharField(max_length=10, + choices=FOLLOW_UP_INCREMENT_UNIT_CHOICE.items(), + verbose_name='Units for the follow up incrementals', + help_text='Units for the number of days between visits for both patients and controls', + default=FOLLOW_UP_INCREMENT_IN_YEARS, + blank=False + ) + def check_nd_number(self, nd_number): regex = re.compile(self.nd_number_study_subject_regex) return regex.match(nd_number) is not None diff --git a/smash/web/models/visit.py b/smash/web/models/visit.py index 47ac3d8a7287d4bc57395a91e265a1b89f49a69f..7025a26c4de156f3097e164059bec46207fb4465 100644 --- a/smash/web/models/visit.py +++ b/smash/web/models/visit.py @@ -1,11 +1,13 @@ # coding=utf-8 import datetime +from dateutil.relativedelta import relativedelta from django.db import models from django.db.models.signals import post_save from django.dispatch import receiver from web.models.constants import BOOL_CHOICES, SUBJECT_TYPE_CHOICES_CONTROL +from web.models import Study class Visit(models.Model): @@ -68,18 +70,19 @@ class Visit(models.Model): follow_up_number = Visit.objects.filter( subject=self.subject).count() + 1 - delta_days = 365 - if self.subject.type == SUBJECT_TYPE_CHOICES_CONTROL: - delta_days = 365 * 3 + 366 + study = self.subject.study - time_to_next_visit = datetime.timedelta( - days=delta_days * (follow_up_number - 1)) + if self.subject.type == SUBJECT_TYPE_CHOICES_CONTROL: + args = {study.default_delta_time_for_follow_up_units: study.default_delta_time_for_control_follow_up} + else: + args = {study.default_delta_time_for_follow_up_units: study.default_delta_time_for_patient_follow_up} + + time_to_next_visit = relativedelta(**args) * (follow_up_number - 1) #calculated from first visit Visit.objects.create( subject=self.subject, datetime_begin=visit_started + time_to_next_visit, - datetime_end=visit_started + time_to_next_visit + - datetime.timedelta(days=93) + datetime_end=visit_started + time_to_next_visit + datetime.timedelta(days=study.default_visit_duration_in_months) ) diff --git a/smash/web/tests/models/test_visit.py b/smash/web/tests/models/test_visit.py index a247d83886c073d3d40d4318949b98817dc7924a..c7d577fe5ab759f4d29d7e104db402fa33c63e78 100644 --- a/smash/web/tests/models/test_visit.py +++ b/smash/web/tests/models/test_visit.py @@ -1,5 +1,5 @@ import datetime - +from dateutil.relativedelta import relativedelta from django.test import TestCase from web.models import Visit @@ -47,7 +47,8 @@ class VisitModelTests(TestCase): visit.mark_as_finished() - follow_up_visit = Visit.objects.filter(subject=subject).filter(visit_number=2)[0] + visit_number=2 + follow_up_visit = Visit.objects.filter(subject=subject).filter(visit_number=visit_number)[0] follow_up_visit.datetime_begin = visit.datetime_begin + datetime.timedelta(days=133) follow_up_visit.datetime_end = visit.datetime_begin + datetime.timedelta(days=170) follow_up_visit.save() @@ -57,10 +58,16 @@ class VisitModelTests(TestCase): visit_count = Visit.objects.filter(subject=subject).count() self.assertEquals(3, visit_count) - new_follow_up = Visit.objects.filter(subject=subject).filter(visit_number=3)[0] + visit_number=3 + new_follow_up = Visit.objects.filter(subject=subject).filter(visit_number=visit_number)[0] # check if follow up date is based on the first visit date - self.assertTrue(visit.datetime_begin + datetime.timedelta(days=365 * 2 - 1) < new_follow_up.datetime_begin) + study = visit.subject.study + args = {study.default_delta_time_for_follow_up_units: study.default_delta_time_for_patient_follow_up} #patient + + time_to_next_visit = relativedelta(**args) * (visit_number - 1) #calculated from first visit + + self.assertTrue(visit.datetime_begin + time_to_next_visit - datetime.timedelta(days=1) < new_follow_up.datetime_begin) def test_visit_to_string(self): visit = create_visit(create_study_subject())