feat(time-blocks): Add seed_holidays management command
🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
201
smoothschedule/schedule/management/commands/seed_holidays.py
Normal file
201
smoothschedule/schedule/management/commands/seed_holidays.py
Normal file
@@ -0,0 +1,201 @@
|
|||||||
|
"""Management command to seed US holidays."""
|
||||||
|
from django.core.management.base import BaseCommand
|
||||||
|
|
||||||
|
from schedule.models import Holiday
|
||||||
|
|
||||||
|
|
||||||
|
US_HOLIDAYS = [
|
||||||
|
# Fixed date holidays
|
||||||
|
{
|
||||||
|
"code": "new_years_day",
|
||||||
|
"name": "New Year's Day",
|
||||||
|
"country": "US",
|
||||||
|
"holiday_type": Holiday.Type.FIXED,
|
||||||
|
"month": 1,
|
||||||
|
"day": 1,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"code": "independence_day",
|
||||||
|
"name": "Independence Day",
|
||||||
|
"country": "US",
|
||||||
|
"holiday_type": Holiday.Type.FIXED,
|
||||||
|
"month": 7,
|
||||||
|
"day": 4,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"code": "veterans_day",
|
||||||
|
"name": "Veterans Day",
|
||||||
|
"country": "US",
|
||||||
|
"holiday_type": Holiday.Type.FIXED,
|
||||||
|
"month": 11,
|
||||||
|
"day": 11,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"code": "christmas_eve",
|
||||||
|
"name": "Christmas Eve",
|
||||||
|
"country": "US",
|
||||||
|
"holiday_type": Holiday.Type.FIXED,
|
||||||
|
"month": 12,
|
||||||
|
"day": 24,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"code": "christmas_day",
|
||||||
|
"name": "Christmas Day",
|
||||||
|
"country": "US",
|
||||||
|
"holiday_type": Holiday.Type.FIXED,
|
||||||
|
"month": 12,
|
||||||
|
"day": 25,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"code": "new_years_eve",
|
||||||
|
"name": "New Year's Eve",
|
||||||
|
"country": "US",
|
||||||
|
"holiday_type": Holiday.Type.FIXED,
|
||||||
|
"month": 12,
|
||||||
|
"day": 31,
|
||||||
|
},
|
||||||
|
# Floating holidays (Nth weekday of month)
|
||||||
|
{
|
||||||
|
"code": "mlk_day",
|
||||||
|
"name": "Martin Luther King Jr. Day",
|
||||||
|
"country": "US",
|
||||||
|
"holiday_type": Holiday.Type.FLOATING,
|
||||||
|
"month": 1,
|
||||||
|
"week_of_month": 3, # 3rd Monday of January
|
||||||
|
"day_of_week": 0, # Monday
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"code": "presidents_day",
|
||||||
|
"name": "Presidents Day",
|
||||||
|
"country": "US",
|
||||||
|
"holiday_type": Holiday.Type.FLOATING,
|
||||||
|
"month": 2,
|
||||||
|
"week_of_month": 3, # 3rd Monday of February
|
||||||
|
"day_of_week": 0, # Monday
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"code": "memorial_day",
|
||||||
|
"name": "Memorial Day",
|
||||||
|
"country": "US",
|
||||||
|
"holiday_type": Holiday.Type.FLOATING,
|
||||||
|
"month": 5,
|
||||||
|
"week_of_month": 5, # Last Monday of May (5 = last)
|
||||||
|
"day_of_week": 0, # Monday
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"code": "juneteenth",
|
||||||
|
"name": "Juneteenth",
|
||||||
|
"country": "US",
|
||||||
|
"holiday_type": Holiday.Type.FIXED,
|
||||||
|
"month": 6,
|
||||||
|
"day": 19,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"code": "labor_day",
|
||||||
|
"name": "Labor Day",
|
||||||
|
"country": "US",
|
||||||
|
"holiday_type": Holiday.Type.FLOATING,
|
||||||
|
"month": 9,
|
||||||
|
"week_of_month": 1, # 1st Monday of September
|
||||||
|
"day_of_week": 0, # Monday
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"code": "columbus_day",
|
||||||
|
"name": "Columbus Day",
|
||||||
|
"country": "US",
|
||||||
|
"holiday_type": Holiday.Type.FLOATING,
|
||||||
|
"month": 10,
|
||||||
|
"week_of_month": 2, # 2nd Monday of October
|
||||||
|
"day_of_week": 0, # Monday
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"code": "thanksgiving",
|
||||||
|
"name": "Thanksgiving Day",
|
||||||
|
"country": "US",
|
||||||
|
"holiday_type": Holiday.Type.FLOATING,
|
||||||
|
"month": 11,
|
||||||
|
"week_of_month": 4, # 4th Thursday of November
|
||||||
|
"day_of_week": 3, # Thursday
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"code": "thanksgiving_friday",
|
||||||
|
"name": "Day After Thanksgiving",
|
||||||
|
"country": "US",
|
||||||
|
"holiday_type": Holiday.Type.FLOATING,
|
||||||
|
"month": 11,
|
||||||
|
"week_of_month": 4, # 4th Friday of November (day after Thanksgiving)
|
||||||
|
"day_of_week": 4, # Friday
|
||||||
|
},
|
||||||
|
# Calculated holidays (Easter-based)
|
||||||
|
{
|
||||||
|
"code": "easter",
|
||||||
|
"name": "Easter Sunday",
|
||||||
|
"country": "US",
|
||||||
|
"holiday_type": Holiday.Type.CALCULATED,
|
||||||
|
"calculation_rule": "easter",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"code": "good_friday",
|
||||||
|
"name": "Good Friday",
|
||||||
|
"country": "US",
|
||||||
|
"holiday_type": Holiday.Type.CALCULATED,
|
||||||
|
"calculation_rule": "easter-2", # 2 days before Easter
|
||||||
|
},
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
|
class Command(BaseCommand):
|
||||||
|
"""Seed US holidays into the database."""
|
||||||
|
|
||||||
|
help = "Seed US holidays for the time blocking system"
|
||||||
|
|
||||||
|
def add_arguments(self, parser):
|
||||||
|
parser.add_argument(
|
||||||
|
"--clear",
|
||||||
|
action="store_true",
|
||||||
|
help="Clear existing holidays before seeding",
|
||||||
|
)
|
||||||
|
|
||||||
|
def handle(self, *args, **options):
|
||||||
|
"""Create or update holiday records."""
|
||||||
|
if options["clear"]:
|
||||||
|
deleted_count, _ = Holiday.objects.filter(country="US").delete()
|
||||||
|
self.stdout.write(
|
||||||
|
self.style.WARNING(f"Deleted {deleted_count} existing US holidays")
|
||||||
|
)
|
||||||
|
|
||||||
|
created_count = 0
|
||||||
|
updated_count = 0
|
||||||
|
|
||||||
|
for holiday_data in US_HOLIDAYS:
|
||||||
|
code = holiday_data["code"]
|
||||||
|
holiday, created = Holiday.objects.update_or_create(
|
||||||
|
code=code,
|
||||||
|
defaults=holiday_data,
|
||||||
|
)
|
||||||
|
if created:
|
||||||
|
created_count += 1
|
||||||
|
self.stdout.write(f" Created: {holiday.name}")
|
||||||
|
else:
|
||||||
|
updated_count += 1
|
||||||
|
self.stdout.write(f" Updated: {holiday.name}")
|
||||||
|
|
||||||
|
self.stdout.write(
|
||||||
|
self.style.SUCCESS(
|
||||||
|
f"\nDone! Created {created_count}, updated {updated_count} holidays."
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
# Show sample dates for the current year
|
||||||
|
from datetime import date
|
||||||
|
current_year = date.today().year
|
||||||
|
self.stdout.write(f"\nHoliday dates for {current_year}:")
|
||||||
|
for holiday in Holiday.objects.filter(country="US", is_active=True).order_by("month", "day"):
|
||||||
|
try:
|
||||||
|
holiday_date = holiday.get_date_for_year(current_year)
|
||||||
|
if holiday_date:
|
||||||
|
self.stdout.write(f" {holiday.name}: {holiday_date.strftime('%B %d, %Y')}")
|
||||||
|
except Exception as e:
|
||||||
|
self.stdout.write(
|
||||||
|
self.style.ERROR(f" {holiday.name}: Error calculating date - {e}")
|
||||||
|
)
|
||||||
Reference in New Issue
Block a user