diff --git a/smash/smash/settings.py b/smash/smash/settings.py index b443f11026c2192d8bcfe0138e6027aed8272d5a..a327ecd64d4221f67bb45935c18143dd119c462f 100644 --- a/smash/smash/settings.py +++ b/smash/smash/settings.py @@ -74,6 +74,7 @@ TEMPLATES = [ CRON_CLASSES = [ 'web.views.kit.KitRequestEmailSendJob', + 'web.views.virus_mail.KitRequestEmailSendJob', 'web.redcap_connector.RedCapRefreshJob', 'web.views.voucher.ExpireVouchersJob', 'web.importer.exporter_cron_job.SubjectExporterCronJob', diff --git a/smash/web/migrations/0165_configurationitem_email_virus.py b/smash/web/migrations/0165_configurationitem_email_virus.py new file mode 100644 index 0000000000000000000000000000000000000000..0feeb5ddfd2fe8a12f49e8baf4d858b4ebf78438 --- /dev/null +++ b/smash/web/migrations/0165_configurationitem_email_virus.py @@ -0,0 +1,33 @@ +# -*- coding: utf-8 -*- +# Generated by Django 1.10.3 on 2017-04-04 09:43 +from __future__ import unicode_literals + +from django.db import migrations + +from web.models.constants import VIRUS_EMAIL_HOUR_CONFIGURATION_TYPE + + +def create_item(apps, type, value, name): + # We can't import the ConfigurationItem model directly as it may be a newer + # version than this migration expects. We use the historical version. + ConfigurationItem = apps.get_model("web", "ConfigurationItem") + item = ConfigurationItem.objects.create() + item.type = type + item.value = value + item.name = name + item.save() + + +def configuration_items(apps, schema_editor): + create_item(apps, VIRUS_EMAIL_HOUR_CONFIGURATION_TYPE, "", + "At what time a day email with updates about virus tests should be sent") + + +class Migration(migrations.Migration): + dependencies = [ + ('web', '0164_configurationitem_email_items_for_redcap'), + ] + + operations = [ + migrations.RunPython(configuration_items), + ] diff --git a/smash/web/models/constants.py b/smash/web/models/constants.py index 049ea7071637c6f48b51f4063d3fd26fb15b08d6..361c158e015311d495803b3073978541e978f0c6 100644 --- a/smash/web/models/constants.py +++ b/smash/web/models/constants.py @@ -51,6 +51,7 @@ KIT_EMAIL_HOUR_CONFIGURATION_TYPE = "KIT_DAILY_EMAIL_HOUR_CONFIGURATION_TYPE" KIT_EMAIL_DAY_OF_WEEK_CONFIGURATION_TYPE = "KIT_EMAIL_DAY_OF_WEEK_CONFIGURATION_TYPE" KIT_DAILY_EMAIL_DAYS_PERIOD_TYPE = "KIT_DAILY_EMAIL_DAYS_PERIOD_TYPE" KIT_DAILY_EMAIL_TIME_FORMAT_TYPE = "KIT_DAILY_EMAIL_TIME_FORMAT_TYPE" +VIRUS_EMAIL_HOUR_CONFIGURATION_TYPE = "VIRUS_EMAIL_HOUR_CONFIGURATION_TYPE" RED_CAP_LANGUAGE_4_FIELD_TYPE = 'RED_CAP_LANGUAGE_4_FIELD_TYPE' RED_CAP_LANGUAGE_3_FIELD_TYPE = 'RED_CAP_LANGUAGE_3_FIELD_TYPE' @@ -64,6 +65,7 @@ RED_CAP_ND_NUMBER_FIELD_TYPE = 'RED_CAP_ND_NUMBER_FIELD_TYPE' RED_CAP_VIRUS_FIELD_TYPE = 'RED_CAP_VIRUS_FIELD_TYPE' RED_CAP_SAMPLE_DATE_FIELD_TYPE = "RED_CAP_SAMPLE_DATE_FIELD_TYPE" + MAIL_TEMPLATE_CONTEXT_SUBJECT = 'S' MAIL_TEMPLATE_CONTEXT_APPOINTMENT = 'A' MAIL_TEMPLATE_CONTEXT_VISIT = 'V' diff --git a/smash/web/redcap_connector.py b/smash/web/redcap_connector.py index df68598c5d44561d5408f067455485bddf52eb84..efbc6a3f883c0d6bf22fbdb5125c34b201af9c29 100644 --- a/smash/web/redcap_connector.py +++ b/smash/web/redcap_connector.py @@ -43,6 +43,7 @@ class RedcapSubject(object): class RedcapVisit(object): virus = None + virus_inconclusive = False visit_number = 0 @@ -218,6 +219,21 @@ class RedcapConnector(object): subject.virus_test_5 = visit.virus subject.virus_test_5_updated = datetime.datetime.now() subject.save() + if visit.visit_number == 1 and subject.virus_test_1_updated is None and visit.virus_inconclusive: + subject.virus_test_1_updated = datetime.datetime.now() + subject.save() + if visit.visit_number == 2 and subject.virus_test_2_updated is None and visit.virus_inconclusive: + subject.virus_test_2_updated = datetime.datetime.now() + subject.save() + if visit.visit_number == 3 and subject.virus_test_3_updated is None and visit.virus_inconclusive: + subject.virus_test_3_updated = datetime.datetime.now() + subject.save() + if visit.visit_number == 4 and subject.virus_test_4_updated is None and visit.virus_inconclusive: + subject.virus_test_4_updated = datetime.datetime.now() + subject.save() + if visit.visit_number == 5 and subject.virus_test_5_updated is None and visit.virus_inconclusive: + subject.virus_test_5_updated = datetime.datetime.now() + subject.save() return result @@ -330,6 +346,8 @@ class RedcapConnector(object): visit.virus = False elif row.get(self.virus_field) == "Positive": visit.virus = True + elif row.get(self.virus_field) == "Inconclusive": + visit.virus_inconclusive = True if self.sample_date_field != "": if row.get(self.sample_date_field) != "": redcap_subject.visits.append(visit) diff --git a/smash/web/views/virus_mail.py b/smash/web/views/virus_mail.py new file mode 100644 index 0000000000000000000000000000000000000000..2cf38c38e3602446fba53e15efdd19efe6aa6639 --- /dev/null +++ b/smash/web/views/virus_mail.py @@ -0,0 +1,103 @@ +# coding=utf-8 +import datetime +import logging + +import timeout_decorator +from django_cron import CronJobBase, Schedule + +from web.models import ConfigurationItem +from web.models.constants import VIRUS_EMAIL_HOUR_CONFIGURATION_TYPE, \ + CRON_JOB_TIMEOUT +from ..models import StudySubject, Worker +from ..smash_email import EmailSender + +logger = logging.getLogger(__name__) + + +def get_subject_statistics(): + date_from = datetime.datetime.now() - datetime.timedelta(days=1) + + subjects_positive_count = StudySubject.objects.filter(virus_test_1_updated__gt=date_from, virus_test_1=True).count() + subjects_positive_count += StudySubject.objects.filter(virus_test_2_updated__gt=date_from, + virus_test_2=True).count() + subjects_positive_count += StudySubject.objects.filter(virus_test_3_updated__gt=date_from, + virus_test_3=True).count() + subjects_positive_count += StudySubject.objects.filter(virus_test_4_updated__gt=date_from, + virus_test_4=True).count() + subjects_positive_count += StudySubject.objects.filter(virus_test_5_updated__gt=date_from, + virus_test_5=True).count() + + subjects_negative_count = StudySubject.objects.filter(virus_test_1_updated__gt=date_from, + virus_test_1=False).count() + subjects_negative_count += StudySubject.objects.filter(virus_test_2_updated__gt=date_from, + virus_test_2=False).count() + subjects_negative_count += StudySubject.objects.filter(virus_test_3_updated__gt=date_from, + virus_test_3=False).count() + subjects_negative_count += StudySubject.objects.filter(virus_test_4_updated__gt=date_from, + virus_test_4=False).count() + subjects_negative_count += StudySubject.objects.filter(virus_test_5_updated__gt=date_from, + virus_test_5=False).count() + + subjects_inconclusive_count = StudySubject.objects.filter(virus_test_1_updated__gt=date_from, + virus_test_1__isnull=True).count() + subjects_inconclusive_count += StudySubject.objects.filter(virus_test_2_updated__gt=date_from, + virus_test_2__isnull=True).count() + subjects_inconclusive_count += StudySubject.objects.filter(virus_test_3_updated__gt=date_from, + virus_test_3__isnull=True).count() + subjects_inconclusive_count += StudySubject.objects.filter(virus_test_4_updated__gt=date_from, + virus_test_4__isnull=True).count() + subjects_inconclusive_count += StudySubject.objects.filter(virus_test_5_updated__gt=date_from, + virus_test_5__isnull=True).count() + + return {"Positive": subjects_positive_count, "Negative": subjects_negative_count, + "Inconclusive": subjects_inconclusive_count, + "total": subjects_positive_count + subjects_negative_count + subjects_inconclusive_count} + + +def create_statistic_email_content(data, title): + email_body = "<h1>" + title + "</h1>" + + email_body += "In the past 24 hours " + str(data["total"]) + " donors were tested</br></br>" + for status in data: + if status != "total": + email_body += str(data[status]) + ' number of donors were tested ' + status + "</br>" + + return email_body + + +def send_mail(data): + title = "Virus test statistics" + email_body = create_statistic_email_content(data, title) + + recipients = [] + workers = Worker.objects.all() + for worker in workers: + if worker.user is not None: + if worker.user.is_active: + if worker.email is not None and worker.email != "": + recipients.append(worker.email) + cc_recipients = [] + logger.warn('Calling to send email') + EmailSender().send_email(title, email_body, ";".join(recipients), cc_recipients) + + +class KitRequestEmailSendJob(CronJobBase): + RUN_AT = [] + + try: + times = ConfigurationItem.objects.get( + type=VIRUS_EMAIL_HOUR_CONFIGURATION_TYPE).value.split(";") + for entry in times: + # TODO it's a hack assuming that we are in CEST + text = str((int(entry.split(":")[0]) + 22) % 24) + ":" + entry.split(":")[1] + RUN_AT.append(text) + except: + logger.error("Cannot fetch data about email hour") + schedule = Schedule(run_at_times=RUN_AT) + code = 'web.virus_daily_email' # a unique code + + @timeout_decorator.timeout(CRON_JOB_TIMEOUT) + def do(self): + data = get_subject_statistics() + send_mail(data) + return "mail sent"