Skip to content
Snippets Groups Projects
test_office_availability.py 12.6 KiB
Newer Older
import logging

from django.test import TestCase
from django.utils import timezone
import datetime
import pandas as pd
from datetime import timedelta
from functions import create_availability, create_visit, create_appointment, create_appointment_type
from web.utils import get_weekdays_in_period
from web.officeAvailability import OfficeAvailability
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
from web.models.constants import AVAILABILITY_HOLIDAY, AVAILABILITY_EXTRA
from web.tests.functions import create_worker

logger = logging.getLogger(__name__)

class OfficeAvailabilityTest(TestCase):
	def test_availability_cases(self):
		#
		today = timezone.now()
		start_date = datetime.datetime(today.year, today.month, today.day, tzinfo=today.tzinfo) #today midnight
		end_date = start_date + datetime.timedelta(days=1)

		office_availability = OfficeAvailability('FirstName LastName', 
			start=start_date, end=end_date, office_start='8:00', office_end='18:00')
		
		#no availabilties added yet
		self.assertEqual(office_availability.is_available(), False)
		self.assertEqual(office_availability.is_available(only_working_hours=True), False)
		self.assertEqual(office_availability.get_availability_percentage(only_working_hours=True), 0.0)
		self.assertEqual(office_availability.get_availability_percentage(only_working_hours=False), 0.0)

		#add availabilty from 8:00 to 18:00
		weekday = list(get_weekdays_in_period(start_date, end_date))[0]
		availability = create_availability(available_from='8:00', available_till='18:00', day_number=weekday)
		office_availability.consider_this(availability)
		self.assertEqual(office_availability.is_available(only_working_hours=True), True)
		self.assertEqual(office_availability.is_available(), False) #less than 50%
		self.assertEqual(office_availability.get_availability_percentage(only_working_hours=True), 100.0)
		self.assertEqual(office_availability.get_availability_percentage(only_working_hours=False), 41.70714781401804) # ((10*(60)+1)/(24*60.0+1))*100 That +1 is the zero minute

		#add holiday from 16:00 to 18:00 # 2 hours less availability
		start_date = datetime.datetime(today.year, today.month, today.day, 16, 00, tzinfo=today.tzinfo)
		end_date = start_date + datetime.timedelta(hours=2)
		holiday = Holiday(person=create_worker(), datetime_start=start_date, datetime_end=end_date, kind=AVAILABILITY_HOLIDAY)
		office_availability.consider_this(holiday)
		self.assertEqual(office_availability.is_available(only_working_hours=True), True)
		self.assertEqual(office_availability.is_available(), False)  #less than 50%
		self.assertEqual(office_availability.get_availability_percentage(only_working_hours=True), 79.86688851913478) # ((8*60)/(10*60.0+1))*100  # the bordwer minute is 0, then no +1
		self.assertEqual(office_availability.get_availability_percentage(only_working_hours=False), 33.31020124913255) # ((8*60)/(24*60.0+1))*100
		
		#add extra availability from 17:00 to 18:00 # 1 hour more availability 
		start_date = datetime.datetime(today.year, today.month, today.day, 17, 00, tzinfo=today.tzinfo)
		end_date = start_date + datetime.timedelta(hours=1)
		extra_availability = Holiday(person=create_worker(), datetime_start=start_date, datetime_end=end_date, kind=AVAILABILITY_EXTRA)
		office_availability.consider_this(extra_availability)
		self.assertEqual(office_availability.is_available(only_working_hours=True), True)
		self.assertEqual(office_availability.is_available(), False)  #less than 50%
		self.assertEqual(office_availability.get_availability_percentage(only_working_hours=True), 90.01663893510815) # ((9*60+1)/(10*60.0+1))*100 # the border minute is now 1 then +1
		self.assertEqual(office_availability.get_availability_percentage(only_working_hours=False), 37.543372657876475)
		
		#add appointment from 9:00 to 10:00 # 1 hour less availability
			#create visit
		visit_start_date = start_date - datetime.timedelta(days=31)
		visit_end_date   = end_date + datetime.timedelta(days=31)
		visit = create_visit(subject=None, datetime_begin=visit_start_date, datetime_end=visit_end_date)
			#create appointment
		appointment_typeA = create_appointment_type(code='A', default_duration=40, description='test1')
		appointment_typeB = create_appointment_type(code='B', default_duration=20, description='test2')
		appointment_when = datetime.datetime(today.year, today.month, today.day, 9, 00, tzinfo=today.tzinfo)
		appointment = create_appointment(visit=visit, when=appointment_when, length=60)
		worker = create_worker()
		app_type_linkA = AppointmentTypeLink(appointment=appointment, date_when=appointment_when, appointment_type=appointment_typeA, worker=worker)
		app_type_linkB = AppointmentTypeLink(appointment=appointment, date_when=appointment_when+datetime.timedelta(minutes=20), appointment_type=appointment_typeB, worker=worker)
		appointment.save()
		#the availability percentage should be the same as before adding the extra availability
		office_availability.consider_this(appointment)
		self.assertEqual(office_availability.is_available(only_working_hours=True), True)
		self.assertEqual(office_availability.is_available(), False)  #less than 50%
		self.assertEqual(office_availability.get_availability_percentage(only_working_hours=True), 79.86688851913478) # ((8*60)/(10*60.0+1))*100  # the bordwer minute is 0, then no +1
		self.assertEqual(office_availability.get_availability_percentage(only_working_hours=False), 33.31020124913255) # ((8*60)/(24*60.0+1))*100
		#consider the 2 AppointmentTypeLinks. The availability percentage shouldn't change
		office_availability.consider_this(app_type_linkA)
		office_availability.consider_this(app_type_linkB)
		self.assertEqual(office_availability.is_available(only_working_hours=True), True)
		self.assertEqual(office_availability.is_available(), False)  #less than 50%
		self.assertEqual(office_availability.get_availability_percentage(only_working_hours=True), 79.86688851913478) # ((8*60)/(10*60.0+1))*100  # the bordwer minute is 0, then no +1
		self.assertEqual(office_availability.get_availability_percentage(only_working_hours=False), 33.31020124913255) # ((8*60)/(24*60.0+1))*100

		#force add availability from 9:00 to 10:00 # 1 hour more availability
		start_date = datetime.datetime(today.year, today.month, today.day, 9, 00, tzinfo=today.tzinfo).replace(second=0, microsecond=0)
		end_date = start_date + datetime.timedelta(hours=1)
		office_availability.add_availability(pd.date_range(start=start_date, end=end_date, freq='1T'), only_working_hours=False)
		self.assertEqual(office_availability.is_available(only_working_hours=True), True)
		self.assertEqual(office_availability.is_available(), False)  #less than 50%
		self.assertEqual(office_availability.get_availability_percentage(only_working_hours=True), 90.01663893510815) # ((9*60+1)/(10*60.0+1))*100 # the border minute is now 1 then +1
		self.assertEqual(office_availability.get_availability_percentage(only_working_hours=False), 37.543372657876475)

		#force remove availability from 9:00 to 12:00 # 3 hour less availability
		start_date = datetime.datetime(today.year, today.month, today.day, 9, 00, tzinfo=today.tzinfo).replace(second=0, microsecond=0)
		end_date = start_date + datetime.timedelta(hours=3)
		office_availability.remove_availability(pd.date_range(start=start_date, end=end_date, freq='1T'), only_working_hours=True)
		self.assertEqual(office_availability.is_available(only_working_hours=True), True)
		self.assertEqual(office_availability.is_available(), False)  #less than 50%
		self.assertEqual(office_availability.get_availability_percentage(only_working_hours=True), 59.900166389351085) # ((6*60)/(10*60.0+1))*100 # the border minute is 0 then no +1
		self.assertEqual(office_availability.get_availability_percentage(only_working_hours=False), 24.98265093684941)

	def test_availability_cases2(self):
		#
		today = timezone.now()
		start_date = datetime.datetime(today.year, today.month, today.day, tzinfo=today.tzinfo) #today midnight
		end_date = start_date + datetime.timedelta(days=1)

		first_name = u'âêîôûŵŷäëïöüẅÿà'
		last_name = u'èìòùẁỳáéíóúẃýćńóśźżąę'
		office_availability = OfficeAvailability(u'{} {}'.format(first_name, last_name), 
			start=start_date, end=end_date, office_start='8:00', office_end='18:00')
		
		#no availabilties added yet
		self.assertEqual(office_availability.is_available(), False)
		self.assertEqual(office_availability.is_available(only_working_hours=True), False)
		self.assertEqual(office_availability.get_availability_percentage(only_working_hours=True), 0.0)
		self.assertEqual(office_availability.get_availability_percentage(only_working_hours=False), 0.0)

		#add availabilty from 8:00 to 18:00
		weekday = list(get_weekdays_in_period(start_date, end_date))[0]
		availability = create_availability(available_from='8:00', available_till='18:00', day_number=weekday)
		office_availability.consider_this(availability)
		self.assertEqual(office_availability.is_available(only_working_hours=True), True)
		self.assertEqual(office_availability.is_available(), False) #less than 50%
		self.assertEqual(office_availability.get_availability_percentage(only_working_hours=True), 100.0)
		self.assertEqual(office_availability.get_availability_percentage(only_working_hours=False), 41.70714781401804) # ((10*(60)+1)/(24*60.0+1))*100 That +1 is the zero minute

		#add holiday (leave) from 30 days ago up to next 90 days starting with today in the middle
		start_date = datetime.datetime(today.year, today.month, today.day, 16, 00, tzinfo=today.tzinfo)
		end_date = start_date + datetime.timedelta(days=90)
		start_date = start_date - datetime.timedelta(days=30)
		holiday = Holiday(person=create_worker(), datetime_start=start_date, datetime_end=end_date, kind=AVAILABILITY_HOLIDAY)
		office_availability.consider_this(holiday)
		self.assertEqual(office_availability.is_available(only_working_hours=True), False)
		self.assertEqual(office_availability.is_available(), False)  #less than 50%
		self.assertEqual(office_availability.get_availability_percentage(only_working_hours=True), 0) # ((8*60)/(10*60.0+1))*100  # the bordwer minute is 0, then no +1
		self.assertEqual(office_availability.get_availability_percentage(only_working_hours=False), 0) # ((8*60)/(24*60.0+1))*100

	def test_availability_cases3(self):
		#
		today = timezone.now()
		start_date = datetime.datetime(today.year, today.month, today.day, tzinfo=today.tzinfo) #today midnight
		end_date = start_date + datetime.timedelta(days=1)

		first_name = u'âêîôûŵŷäëïöüẅÿà'
		last_name = u'èìòùẁỳáéíóúẃýćńóśźżąę'
		office_availability = OfficeAvailability(u'{} {}'.format(first_name, last_name), 
			start=start_date, end=end_date, office_start='8:00', office_end='18:00')
		
		#no availabilties added yet
		self.assertEqual(office_availability.is_available(), False)
		self.assertEqual(office_availability.is_available(only_working_hours=True), False)
		self.assertEqual(office_availability.get_availability_percentage(only_working_hours=True), 0.0)
		self.assertEqual(office_availability.get_availability_percentage(only_working_hours=False), 0.0)
		#add availabilty from 8:00 to 18:00
		weekday = list(get_weekdays_in_period(start_date, end_date))[0]
		availability = create_availability(available_from='8:00', available_till='18:00', day_number=weekday)
		office_availability.consider_this(availability)
		self.assertEqual(office_availability.is_available(only_working_hours=True), True)
		self.assertEqual(office_availability.is_available(), False) #less than 50%
		self.assertEqual(office_availability.get_availability_percentage(only_working_hours=True), 100.0)
		self.assertEqual(office_availability.get_availability_percentage(only_working_hours=False), 41.70714781401804) # ((10*(60)+1)/(24*60.0+1))*100 That +1 is the zero minute
		#add holiday (leave) from 90 days ago up to 60 days ago but without overlapping with today's date
		start_date = datetime.datetime(today.year, today.month, today.day, 16, 00, tzinfo=today.tzinfo) - datetime.timedelta(days=90)
		end_date = start_date + datetime.timedelta(days=30)
		holiday = Holiday(person=create_worker(), datetime_start=start_date, datetime_end=end_date, kind=AVAILABILITY_HOLIDAY)
		office_availability.consider_this(holiday)
		self.assertEqual(office_availability.is_available(only_working_hours=True), True)
		self.assertEqual(office_availability.is_available(), False)  #less than 50%
		self.assertEqual(office_availability.get_availability_percentage(only_working_hours=True), 100.0) # ((8*60)/(10*60.0+1))*100  # the bordwer minute is 0, then no +1
		self.assertEqual(office_availability.get_availability_percentage(only_working_hours=False), 41.70714781401804) # ((8*60)/(24*60.0+1))*100