Skip to content
Snippets Groups Projects
worker.py 11.3 KiB
Newer Older
# coding=utf-8
import datetime
import logging
from web.utils import get_today_midnight_date

from django.contrib.auth.models import User, AnonymousUser
from django.db import models

from web.models.constants import GLOBAL_STUDY_ID, COUNTRY_OTHER_ID, AVAILABILITY_HOLIDAY, AVAILABILITY_EXTRA
from web.models.worker_study_role import STUDY_ROLE_CHOICES, HEALTH_PARTNER_ROLE_CHOICES, \
    VOUCHER_PARTNER_ROLE_CHOICES, WORKER_STAFF, WORKER_HEALTH_PARTNER, WORKER_VOUCHER_PARTNER, ROLE_CHOICES
from web.utils import get_weekdays_in_period
from web.officeAvailability import OfficeAvailability
from django.db.models import Q
from web.models.holiday import Holiday
from web.models.availability import Availability
from web.models.appointment import Appointment
from web.models.appointment_type_link import AppointmentTypeLink

logger = logging.getLogger(__name__)

def roles_by_worker_type(worker_type):
    role_choices = role_choices_by_worker_type(worker_type)
    roles = []

    for role_type, role_name in role_choices:
        roles.append(role_type)
    return roles


def role_choices_by_worker_type(worker_type):
    if worker_type == WORKER_STAFF:
        return STUDY_ROLE_CHOICES
    elif worker_type == WORKER_HEALTH_PARTNER:
        return HEALTH_PARTNER_ROLE_CHOICES
    elif worker_type == WORKER_VOUCHER_PARTNER:
        return VOUCHER_PARTNER_ROLE_CHOICES
    else:
        raise TypeError("Unknown worker type")


def worker_type_by_worker(worker):
    roles = worker.roles.filter(study=GLOBAL_STUDY_ID)
    if roles.count() == 0:
        return WORKER_STAFF
    role = roles[0].role
    for role_type, role_name in STUDY_ROLE_CHOICES:
        if role_type == role:
            return WORKER_STAFF
    for role_type, role_name in HEALTH_PARTNER_ROLE_CHOICES:
        if role_type == role:
            return WORKER_HEALTH_PARTNER
    for role_type, role_name in VOUCHER_PARTNER_ROLE_CHOICES:
        if role_type == role:
            return WORKER_VOUCHER_PARTNER
    raise TypeError("Unknown worker role")
class Worker(models.Model):
    class Meta:
        app_label = 'web'

    languages = models.ManyToManyField("web.Language",
                                       verbose_name='Known languages',
                                       blank=True
                                       )
    locations = models.ManyToManyField("web.Location",
                                       verbose_name='Locations',
                                       blank=True
                                       )
    user = models.OneToOneField(User, blank=True, null=True,
                                verbose_name='Username'
                                )
    first_name = models.CharField(max_length=50,
                                  verbose_name='First name',
                                  blank=True,
                                  )
    last_name = models.CharField(max_length=50,
                                 verbose_name='Last name',
                                 blank=True,
    name = models.CharField(max_length=50,
                            verbose_name='Name',
                            default='',
                            blank=True,
                            null=False
                            )
    phone_number = models.CharField(max_length=20,
                                    verbose_name='Phone number',
                                    blank=True
    phone_number_2 = models.CharField(max_length=20,
                                      verbose_name='Phone number 2',
                                      blank=True
                                      )
    fax_number = models.CharField(max_length=20,
                                  verbose_name='Fax number',
                                  blank=True
                                  )
    address = models.CharField(max_length=255,
                               blank=True,
                               verbose_name='Address'
                               )

    postal_code = models.CharField(max_length=7,
                                   blank=True,
                                   verbose_name='Postal code'
                                   )

    city = models.CharField(max_length=50,
                            blank=True,
                            verbose_name='City'
                            )

    country = models.ForeignKey('web.Country',
                                null=False,
                                blank=False,
                                default=COUNTRY_OTHER_ID,
                                verbose_name='Country'
                                )

    voucher_types = models.ManyToManyField("web.VoucherType",
                                           verbose_name='Voucher types',
                                           blank=True
                                           )

    unit = models.CharField(max_length=50,
                            verbose_name='Unit',
                            blank=True
                            )
    email = models.EmailField(
Piotr Gawron's avatar
Piotr Gawron committed
        verbose_name='E-mail',
        blank=True
    specialization = models.CharField(max_length=20,
                                      verbose_name='Specialization',
                                      blank=True
    voucher_partner_code = models.CharField(max_length=10,
                                            verbose_name='Code',
                                            blank=True
                                            )

    comment = models.TextField(max_length=1024,
                               verbose_name='Comment',
                               null=True,
                               blank=True
                               )

    def is_on_leave(self):
        if len(self.holiday_set.filter(datetime_end__gt=datetime.datetime.now(),
                                       datetime_start__lt=datetime.datetime.now(),
                                        kind=AVAILABILITY_HOLIDAY)):
            return True
        return False

    def disable(self):
        if self.user is not None:
            self.user.is_active = False
            self.user.save()
            logger.info("'" + self.user.username + "' account has been disabled")
            return True
        else:
            logger.warn("Cannot disable account for user '" + self.first_name + " " + self.last_name + "'")
            return False

    def is_active(self):
        if self.user is not None:
            return self.user.is_active
        else:
            return False

    def is_available(self, start_date=None, end_date=None):
        self.availability_percentage(start_date=start_date, end_date=end_date) > 50.0

    def availability_percentage(self, start_date=None, end_date=None):
        '''
            start_date: defaults to None and then is set to today's midnight date 
            end_date: defaults to None and then is set to today's midnight date + 24 hours
        '''
        today_midnight = get_today_midnight_date()

        if start_date is None:
            start_date = today_midnight
        if end_date is None:
            start_date = start_date.replace(hour=0, minute=0, second=0)
            end_date = start_date + datetime.timedelta(days=1)

        office_availability = OfficeAvailability(u'{} {}'.format(self.first_name, self.last_name), start=start_date, end=end_date)
        #Subject Appointments
        old_events = Q(date_when__gt=start_date) & Q(date_when__gt=end_date)
        future_events = Q(date_when__lt=start_date) & Q(date_when__lt=end_date)
        non_overlap_events = old_events | future_events
        overlap_events = ~non_overlap_events
        query = Q(worker=self.id) & overlap_events
        subject_appointments = AppointmentTypeLink.objects.filter(query)
        
        #General Appointments
        old_events = Q(datetime_when__gt=start_date) & Q(datetime_when__gt=end_date)
        future_events = Q(datetime_when__lt=start_date) & Q(datetime_when__lt=end_date)
        non_overlap_events = old_events | future_events
        overlap_events = ~non_overlap_events
        query = Q(worker_assigned=self.id) & overlap_events
        general_appointments = Appointment.objects.filter(query)
        old_events = Q(datetime_start__gt=start_date) & Q(datetime_start__gt=end_date)
        future_events = Q(datetime_end__lt=start_date) & Q(datetime_end__lt=end_date)
        non_overlap_events = old_events | future_events
        overlap_events = ~non_overlap_events
        holidays_and_extra_availabilities = self.holiday_set.filter(overlap_events).order_by('-datetime_start')

        #Availability 
        weekdays = get_weekdays_in_period(start_date, end_date)
        weekdayQ = Q() #create a filter for each weekday in the selected period
        for weekday in weekdays:
            weekdayQ = weekdayQ | Q(day_number=weekday)
        availabilities = self.availability_set.filter(person=self.id).filter(weekdayQ).order_by('day_number', 'available_from')

        things = []
        things.extend(availabilities)
        things.extend(holidays_and_extra_availabilities)
        things.extend(subject_appointments)
        things.extend(general_appointments)
        for thing in things:
            office_availability.consider_this(thing, only_working_hours=True)

        return office_availability.get_availability_percentage(only_working_hours=True)

    @property
    def role(self):
        roles = self.roles.filter(study=GLOBAL_STUDY_ID)
        if roles.count() == 0:
            return WORKER_STAFF
        role = roles[0].role
        if role not in [role_type for role_type, _ in ROLE_CHOICES]:
            raise TypeError("Unknown worker role")
    @staticmethod
    def get_by_user(the_user):
        if isinstance(the_user, User):
            workers = Worker.objects.filter(user=the_user)
            if len(workers) > 0:
                return workers[0]
            else:
                return None
        elif isinstance(the_user, Worker):
            return the_user
        elif isinstance(the_user, AnonymousUser):
            return None
        elif the_user is not None:
            raise TypeError("Unknown class type: " + the_user.__class__.__name__)
        else:
            return None

    @staticmethod
    def get_workers_by_worker_type(worker_type, study_id=GLOBAL_STUDY_ID):
        return Worker.objects.filter(roles__study_id=study_id,
                                     roles__role__in=roles_by_worker_type(worker_type))

    def __str__(self):
        if self.name != '':
            if self.first_name == '':
                return self.name
            else:
                return "%s %s %s" % (self.name, self.first_name, self.last_name)
        else:
            return "%s %s" % (self.first_name, self.last_name)

    def __unicode__(self):
        if self.name != '':
            if self.first_name == '':
                return self.name
            else:
                return "%s %s %s" % (self.name, self.first_name, self.last_name)
        else:
            return "%s %s" % (self.first_name, self.last_name)

    def initials(self):
        result = ""
        if len(self.first_name) > 0:
            result += self.first_name[0]
        if len(self.last_name) > 0:
            result += self.last_name[0]
        return result