Skip to content
Snippets Groups Projects
visit.py 3.72 KiB
Newer Older
# 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


class Visit(models.Model):
    class Meta:
        app_label = 'web'

Carlos Vega's avatar
Carlos Vega committed
    subject = models.ForeignKey("web.StudySubject", on_delete=models.CASCADE, verbose_name='Subject'
                                )
    datetime_begin = models.DateTimeField(
        verbose_name='Visit starts at'
    )
    datetime_end = models.DateTimeField(
        verbose_name='Visit ends at'
    )  # Deadline before which all appointments need to be scheduled

    is_finished = models.BooleanField(
        verbose_name='Has ended',
        default=False
    )
    post_mail_sent = models.BooleanField(choices=BOOL_CHOICES,
                                         verbose_name='Post mail sent',
                                         default=False
                                         )
    appointment_types = models.ManyToManyField("web.AppointmentType",
                                               verbose_name='Requested appointments',
                                               blank=True,
                                               )

    # this value is automatically computed by signal handled by
    # update_visit_number method
    visit_number = models.IntegerField(
        verbose_name='Visit number',
        default=1
    )

    def __unicode__(self):
        return "%s %s" % (self.subject.subject.first_name, self.subject.subject.last_name)

    def __str__(self):
        return "%s %s" % (self.subject.subject.first_name, self.subject.subject.last_name)

    def mark_as_finished(self):
        self.is_finished = True
        self.save()

        create_follow_up = True
        if self.subject.subject.dead:
            create_follow_up = False
        elif self.subject.resigned:
            create_follow_up = False
        elif self.subject.excluded:
            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
            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=study.default_visit_duration_in_months)


@receiver(post_save, sender=Visit)
def update_visit_number(sender, instance, **kwargs):
    visit = instance
    if visit.subject is not None:
        count = Visit.objects.filter(subject=visit.subject).filter(
            datetime_begin__lte=visit.datetime_begin).count()
        if count != visit.visit_number:
            visit.visit_number = count
            visit.save()
            subject_visits = Visit.objects.filter(subject=visit.subject).all()
            for subject_visit in subject_visits:
                update_visit_number(sender, subject_visit)