Initial commit: Parking Manager

Features:
- Manager-centric parking spot management
- Fair assignment algorithm (parking/presence ratio)
- Presence tracking calendar
- Closing days (specific & weekly recurring)
- Guarantees and exclusions
- Authelia/LLDAP integration for SSO

Stack:
- FastAPI backend
- SQLite database
- Vanilla JS frontend
- Docker deployment
This commit is contained in:
Stefano Manfredi
2025-11-26 23:37:50 +00:00
commit c74a0ed350
49 changed files with 9094 additions and 0 deletions

116
services/holidays.py Normal file
View File

@@ -0,0 +1,116 @@
"""
Holiday Service
Configurable holiday calculation for different regions
Currently supports Italian holidays. Can be extended to support other regions
by adding new holiday sets and a configuration option.
"""
from datetime import datetime, date, timedelta
def calculate_easter(year: int) -> date:
"""Calculate Easter Sunday using the Computus algorithm"""
a = year % 19
b = year // 100
c = year % 100
d = b // 4
e = b % 4
f = (b + 8) // 25
g = (b - f + 1) // 3
h = (19 * a + b - d - g + 15) % 30
i = c // 4
k = c % 4
l = (32 + 2 * e + 2 * i - h - k) % 7
m = (a + 11 * h + 22 * l) // 451
month = (h + l - 7 * m + 114) // 31
day = ((h + l - 7 * m + 114) % 31) + 1
return date(year, month, day)
def get_easter_monday(year: int) -> date:
"""Get Easter Monday for a given year"""
easter = calculate_easter(year)
return easter + timedelta(days=1)
# Italian fixed holidays (month, day)
ITALIAN_FIXED_HOLIDAYS = [
(1, 1), # New Year's Day
(1, 6), # Epiphany
(4, 25), # Liberation Day
(5, 1), # Labour Day
(6, 2), # Republic Day
(8, 15), # Assumption
(11, 1), # All Saints
(12, 8), # Immaculate Conception
(12, 25), # Christmas
(12, 26), # St. Stephen's
]
def is_italian_holiday(check_date: date | datetime) -> bool:
"""Check if a date is an Italian public holiday"""
if isinstance(check_date, datetime):
check_date = check_date.date()
year = check_date.year
month = check_date.month
day = check_date.day
# Check fixed holidays
if (month, day) in ITALIAN_FIXED_HOLIDAYS:
return True
# Check Easter Monday
easter_monday = get_easter_monday(year)
if check_date == easter_monday:
return True
return False
def get_holidays_for_year(year: int) -> list[dict]:
"""
Get all holidays for a given year.
Returns list of {date: YYYY-MM-DD, name: string}
"""
holidays = []
# Fixed holidays
holiday_names = [
"New Year's Day", "Epiphany", "Liberation Day", "Labour Day",
"Republic Day", "Assumption", "All Saints", "Immaculate Conception",
"Christmas", "St. Stephen's Day"
]
for (month, day), name in zip(ITALIAN_FIXED_HOLIDAYS, holiday_names):
holidays.append({
"date": f"{year}-{month:02d}-{day:02d}",
"name": name
})
# Easter Monday
easter_monday = get_easter_monday(year)
holidays.append({
"date": easter_monday.strftime("%Y-%m-%d"),
"name": "Easter Monday"
})
# Sort by date
holidays.sort(key=lambda h: h["date"])
return holidays
def is_holiday(check_date: date | datetime | str, region: str = "IT") -> bool:
"""
Check if a date is a holiday for the given region.
Currently only supports IT (Italy).
"""
if isinstance(check_date, str):
check_date = datetime.strptime(check_date, "%Y-%m-%d").date()
if region == "IT":
return is_italian_holiday(check_date)
# Default: no holidays
return False