diff --git a/smash/web/management/__init__.py b/smash/web/management/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/smash/web/management/commands/__init__.py b/smash/web/management/commands/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/smash/web/management/commands/holidays.py b/smash/web/management/commands/holidays.py new file mode 100644 index 0000000000000000000000000000000000000000..cfd82b2870bdc2d2b74cc85c53d8cdacdbc22177 --- /dev/null +++ b/smash/web/management/commands/holidays.py @@ -0,0 +1,94 @@ +import datetime + +from django.core.management.base import BaseCommand + +from ...models import Appointment, Location, AppointmentType + +appointment_type_other = AppointmentType.objects.filter(code='OTHER').first() + + +def get_easter_monday(easter_sunday): + return next_weekday(easter_sunday, 0) + + +def get_ascension_day(easter_sunday): + return easter_sunday + datetime.timedelta(days=39) + + +class Command(BaseCommand): + help = 'import holidays for the specified years' + + def add_arguments(self, parser): + parser.add_argument('year', nargs='+', type=int) + + def handle(self, *args, **options): + for location in Location.objects.all(): + for year in options['year']: + self.stdout.write("importing holidays for year {} and location {}".format(year, location)) + # new years day + self.create_holiday(year, 1, 1, "New Years Day", location) + # easter monday + easter_sunday = get_easter_sunday_date(year) + easter_monday = get_easter_monday(easter_sunday) + self.create_holiday(year, easter_monday.month, easter_monday.day, "Easter Monday", location) + # ascension day + ascension_day = get_ascension_day(easter_sunday) + self.create_holiday(year, ascension_day.month, ascension_day.day, "Ascension Day", location) + # pentecost monday + pentecost_day = get_pentecost_day(easter_sunday) + self.create_holiday(year, pentecost_day.month, pentecost_day.day, "Pentecost Monday", location) + # labour day + self.create_holiday(year, 5, 1, "Labour Day", location) + # national day + self.create_holiday(year, 6, 23, "National Day", location) + # assumption day + self.create_holiday(year, 8, 15, "Assumption Day", location) + # all saints day + self.create_holiday(year, 11, 1, "All Saints Day", location) + # christmas + self.create_holiday(year, 12, 25, "Christmas Day", location) + self.create_holiday(year, 12, 26, "St Stephens Day", location) + + def create_holiday(self, year, month, day, comment, location): + # check if already exists: + count = Appointment.objects.filter(datetime_when__year=year, datetime_when__month=month, datetime_when__day=day, + location=location, comment=comment).count() + if count != 0: + self.stdout.write( + 'an holiday with the same description already exists for the same day: {}'.format(comment)) + return + holiday = Appointment() + holiday.datetime_when = datetime.datetime(year=year, month=month, day=day, hour=9) + holiday.location = location + holiday.length = 60 * 8 + holiday.comment = comment + holiday.visit_id = None + holiday.save() + holiday.appointment_types = [appointment_type_other] + + +def get_easter_sunday_date(year): + # source: http://www.officeholidays.com/religious/christian/easter_monday.php + c = year // 100 + n = year - 19 * (year // 19) + k = (c - 17) // 25 + i = c - c // 4 - (c - k) // 3 + 19 * n + 15 + i = i - 30 * (i // 30) + i = i - (i // 28) * (1 - (i // 28) * (29 // (i + 1)) * ((21 - n) // 11)) + j = year + year // 4 + i + 2 - c + c // 4 + j = j - 7 * (j // 7) + l = i - j + month = 3 + (l + 40) // 44 + day = l + 28 - 31 * (month // 4) + return datetime.datetime(year=year, month=month, day=day) + + +def get_pentecost_day(easter_sunday): + return easter_sunday + datetime.timedelta(days=50) + + +def next_weekday(day_datetime, week_day): + days_ahead = week_day - day_datetime.weekday() + if days_ahead <= 0: + days_ahead += 7 + return day_datetime + datetime.timedelta(days_ahead) diff --git a/smash/web/tests/test_holidays.py b/smash/web/tests/test_holidays.py new file mode 100644 index 0000000000000000000000000000000000000000..2bcfeac8ede5f9ca2a354dfb1936d2918d4feac8 --- /dev/null +++ b/smash/web/tests/test_holidays.py @@ -0,0 +1,39 @@ +from unittest import TestCase + +from web.management.commands.holidays import get_easter_sunday_date, get_ascension_day, get_pentecost_day + + +class TestHolidays(TestCase): + def test_get_easter_sunday_date(self): + easter_sunday = get_easter_sunday_date(2010) + self.assertEqual(4, easter_sunday.month) + self.assertEqual(4, easter_sunday.day) + easter_sunday = get_easter_sunday_date(2017) + self.assertEqual(4, easter_sunday.month) + self.assertEqual(16, easter_sunday.day) + + def test_get_ascension_day(self): + expected_values = [ + (2018, 5, 10), + (2017, 5, 25), + (2016, 5, 5), + (2015, 5, 14), + (2014, 5, 29) + ] + for year, month, day in expected_values: + easter_sunday = get_easter_sunday_date(year) + ascension_day = get_ascension_day(easter_sunday) + self.assertEqual(month, ascension_day.month) + self.assertEqual(day, ascension_day.day) + + def test_get_pentecost_day(self): + expected_values = [ + (2018, 5, 21), + (2017, 6, 5), + (2016, 5, 16), + ] + for year, month, day in expected_values: + easter_sunday = get_easter_sunday_date(year) + pentecost_day = get_pentecost_day(easter_sunday) + self.assertEqual(month, pentecost_day.month) + self.assertEqual(day, pentecost_day.day)