Skip to content
Snippets Groups Projects
study_subject_forms.py 9.05 KiB
Newer Older
import re

from django import forms
from django.forms import ModelForm

from web.forms.forms import DATETIMEPICKER_DATE_ATTRS, get_worker_from_args
from web.models import StudySubject, Study, StudyColumns, VoucherType, Worker
from web.models.constants import SCREENING_NUMBER_PREFIXES_FOR_TYPE
from web.models.worker_study_role import WORKER_HEALTH_PARTNER
Piotr Gawron's avatar
Piotr Gawron committed
from web.widgets.secure_file_widget import SecuredFileWidget
logger = logging.getLogger(__name__)

Piotr Gawron's avatar
Piotr Gawron committed
class StudySubjectForm(ModelForm):
Carlos Vega's avatar
Carlos Vega committed
    datetime_contact_reminder = forms.DateTimeField(label="Contact on", widget=forms.DateTimeInput(DATETIMEPICKER_DATE_ATTRS), required=False)
    referral_letter = forms.FileField(label='Referral letter', widget=SecuredFileWidget(), required=False)
    voucher_types = forms.ModelMultipleChoiceField(required=False, widget=forms.CheckboxSelectMultiple, queryset=VoucherType.objects.all())
Piotr Gawron's avatar
Piotr Gawron committed

    def __init__(self, *args, **kwargs):
        super(StudySubjectForm, self).__init__(*args, **kwargs)
        self.fields['health_partner'].queryset = Worker.get_workers_by_worker_type(
            WORKER_HEALTH_PARTNER)
Piotr Gawron's avatar
Piotr Gawron committed


class StudySubjectAddForm(StudySubjectForm):
    class Meta:
        model = StudySubject
        fields = '__all__'
        exclude = ['resigned', 'resign_reason']

    def __init__(self, *args, **kwargs):
        self.user = get_worker_from_args(kwargs)
        self.study = get_study_from_args(kwargs)

Piotr Gawron's avatar
Piotr Gawron committed
        super(StudySubjectAddForm, self).__init__(*args, **kwargs)
        prepare_study_subject_fields(fields=self.fields, study=self.study)

    def save(self, commit=True):
        self.instance.study_id = self.study.id
Piotr Gawron's avatar
Piotr Gawron committed
        return super(StudySubjectAddForm, self).save(commit)

    def build_screening_number(self, cleaned_data):
        screening_number = cleaned_data.get('screening_number', None)
        if not screening_number:
            prefix_screening_number = self.get_prefix_screening_number()
            if prefix_screening_number is not None:
Carlos Vega's avatar
Carlos Vega committed
                screening_number = get_new_screening_number(prefix_screening_number)
        return screening_number

    def clean(self):
        cleaned_data = super(StudySubjectAddForm, self).clean()
        screening_number = self.build_screening_number(cleaned_data)
        if screening_number is not None and self.study.columns.screening_number:
            cleaned_data['screening_number'] = screening_number
        validate_subject_screening_number(self, cleaned_data)
        validate_subject_nd_number(self, cleaned_data)
        validate_subject_mpower_number(self, cleaned_data)
        return cleaned_data

    def get_prefix_screening_number(self):
        default_location = self.cleaned_data.get('default_location', None)
        screening_number_prefix = None
        if default_location is not None and default_location.prefix:
            screening_number_prefix = default_location.prefix
        else:
            subject_type = self.cleaned_data.get('type', None)
            if subject_type is not None:
Carlos Vega's avatar
Carlos Vega committed
                screening_number_prefix = SCREENING_NUMBER_PREFIXES_FOR_TYPE[subject_type]
        if screening_number_prefix is None:
            return None
        prefix_screening_number = screening_number_prefix + "-"
        return prefix_screening_number


def get_new_screening_number(screening_number_prefix):
    result_number = 0
Carlos Vega's avatar
Carlos Vega committed
    subjects = StudySubject.objects.filter(screening_number__contains=screening_number_prefix)
    for subject in subjects:
        screening_numbers = subject.screening_number.split(";")
        for screening_number in screening_numbers:
            screening_number = screening_number.strip()
            if screening_number.startswith(screening_number_prefix):
                number = screening_number[len(screening_number_prefix):]
                try:
                    result_number = max(result_number, int(number))
                except ValueError:
                    pass

    return screening_number_prefix + str(result_number + 1).zfill(3)


Piotr Gawron's avatar
Piotr Gawron committed
class StudySubjectDetailForm(StudySubjectForm):
    class Meta:
        model = StudySubject
        fields = '__all__'

    def __init__(self, *args, **kwargs):
        super(StudySubjectDetailForm, self).__init__(*args, **kwargs)
        instance = getattr(self, 'instance', None)

        self.study = get_study_from_study_subject_instance(instance)

        prepare_study_subject_fields(fields=self.fields, study=self.study)

def get_study_from_study_subject_instance(study_subject):
    if study_subject and study_subject.study_id:
        return Study.objects.filter(id=study_subject.study_id)[0]
        return Study(columns=StudyColumns())
Piotr Gawron's avatar
Piotr Gawron committed
class StudySubjectEditForm(StudySubjectForm):

    def __init__(self, *args, **kwargs):
        was_resigned = kwargs.get('was_resigned', False)
        if 'was_resigned' in kwargs:
            kwargs.pop('was_resigned')
        super(StudySubjectEditForm, self).__init__(*args, **kwargs)
        instance = getattr(self, 'instance', None)
        if instance and instance.id:
            self.fields['screening_number'].widget.attrs['readonly'] = True
        self.study = get_study_from_study_subject_instance(instance)

        if was_resigned:
            self.fields['resigned'].disabled = True

        prepare_study_subject_fields(fields=self.fields, study=self.study)

    def clean(self):
        validate_subject_nd_number(self, self.cleaned_data)
        validate_subject_mpower_number(self, self.cleaned_data)
        validate_subject_resign_reason(self, self.cleaned_data)

    class Meta:
        model = StudySubject
        fields = '__all__'


def get_study_from_args(kwargs):
    study = kwargs.pop('study', None)
    if study is None:
        raise TypeError("Study not defined")
    return study


def prepare_field(fields, visible_columns, field_name, required=False):
Piotr Gawron's avatar
Piotr Gawron committed
    if not getattr(visible_columns, field_name) and field_name in fields:
        del fields[field_name]
    elif required:
        fields[field_name].required = True
def prepare_study_subject_fields(fields, study):
    prepare_field(fields, study.columns, 'default_location', required=True)
    prepare_field(fields, study.columns, 'type', required=True)
    prepare_field(fields, study.columns, 'screening_number')
    prepare_field(fields, study.columns, 'nd_number')
    prepare_field(fields, study.columns, 'datetime_contact_reminder')
    prepare_field(fields, study.columns, 'postponed')
    prepare_field(fields, study.columns, 'excluded')
    prepare_field(fields, study.columns, 'flying_team')
    prepare_field(fields, study.columns, 'mpower_id')
    prepare_field(fields, study.columns, 'comments')
    prepare_field(fields, study.columns, 'referral')
    prepare_field(fields, study.columns, 'diagnosis')
    prepare_field(fields, study.columns, 'year_of_diagnosis')
    prepare_field(fields, study.columns, 'information_sent')
    prepare_field(fields, study.columns, 'pd_in_family')
    prepare_field(fields, study.columns, 'resigned')
    prepare_field(fields, study.columns, 'resign_reason')
Piotr Gawron's avatar
Piotr Gawron committed
    prepare_field(fields, study.columns, 'referral_letter')
    prepare_field(fields, study.columns, 'health_partner')
    prepare_field(fields, study.columns, 'health_partner_feedback_agreement')
    prepare_field(fields, study.columns, 'screening')
    prepare_field(fields, study.columns, 'previously_in_study')
    prepare_field(fields, study.columns, 'voucher_types')


def validate_subject_screening_number(self, cleaned_data):
    if self.study.columns.resign_reason:
        subjects_from_db = StudySubject.objects.filter(screening_number=cleaned_data["screening_number"],
                                                       study=self.study)
        if len(subjects_from_db) > 0:
Carlos Vega's avatar
Carlos Vega committed
            self.add_error('screening_number', "Screening number already in use")


def validate_subject_nd_number(self, cleaned_data):
    if self.study.columns.nd_number:
        nd_number = cleaned_data['nd_number']
        if nd_number != "":
            if not self.study.check_nd_number(nd_number):
                self.add_error('nd_number', "Invalid ND number")
            else:
                subjects_from_db = StudySubject.objects.filter(
                    nd_number=nd_number, study=self.study)
                if subjects_from_db:
                    if subjects_from_db[0].screening_number != cleaned_data.get('screening_number', ''):
                        self.add_error('nd_number', "ND number already in use")


def validate_subject_resign_reason(self, cleaned_data):
    if self.study.columns.resigned and self.study.columns.resign_reason:
        if cleaned_data['resigned'] and cleaned_data['resign_reason'] == '':
            self.add_error('resign_reason', "Resign reason cannot be empty")


def validate_subject_mpower_number(self, cleaned_data):
    if self.study.columns.mpower_id:
        if cleaned_data['mpower_id'] != "":
            subjects_from_db = StudySubject.objects.filter(
                mpower_id=cleaned_data['mpower_id'])
            if subjects_from_db:
                if subjects_from_db[0].screening_number != cleaned_data.get('screening_number', ''):
                    self.add_error('mpower_id', "mPower number already in use")