1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
|
# event_type_handler.py
from datetime import datetime
from dateutil.relativedelta import relativedelta
from typing import List, Dict, Tuple
from calendar_entry import CalendarEntry
from config import EventConfig
from date_service import DateService
class EventTypeHandler:
"""Handles event type-specific business rules and categorization"""
@staticmethod
def get_duration_for_type(event_type: str, start_date: datetime) -> datetime:
"""Calculate end date for event type based on business rules"""
if event_type == "EZ pauschal":
return start_date + EventConfig.get_ez_pauschal_duration()
else:
# For other types, duration is determined by user input
return start_date
@staticmethod
def categorize_events(entries: List[CalendarEntry]) -> Dict[str, List[Tuple[datetime, datetime, str]]]:
"""Categorize calendar entries by type for processing"""
categorized = {}
for entry in entries:
if entry.keyword not in categorized:
categorized[entry.keyword] = []
categorized[entry.keyword].append((
entry.start_date,
entry.end_date,
entry.id
))
return categorized
@staticmethod
def validate_event_type(event_type: str) -> bool:
"""Validate that event type is supported"""
return EventConfig.is_valid_keyword(event_type)
@staticmethod
def get_event_type_display_name(event_type: str) -> str:
"""Get display name for event type"""
display_names = {
"EZ 100%": "Erziehungszeit 100%",
"EZ 50%": "Erziehungszeit 50%",
"EZ pauschal": "Erziehungszeit pauschal",
"Sonstige": "Sonstige Ausfallzeiten"
}
return display_names.get(event_type, event_type)
@staticmethod
def calculate_accounted_time(entry: CalendarEntry) -> str:
"""Calculate the accounted time for an entry based on its type and corrected dates"""
if not entry.corrected_start_date or not entry.corrected_end_date:
return ""
start_dt = entry.corrected_start_date
end_dt = entry.corrected_end_date
if end_dt < start_dt:
return ""
if entry.keyword == "Sonstige":
# For "Sonstige", show days
delta_days = DateService.calculate_days_between(start_dt, end_dt)
return f"{delta_days} Tage"
else:
# For EZ types, show months
total_months = DateService.calculate_months_between(start_dt, end_dt)
if entry.keyword == "EZ 50%":
# Half-time projects count as half months
total_months = (total_months + 1) // 2 # Round up
return f"{total_months} Monate"
@staticmethod
def should_hide_end_date_input(event_type: str) -> bool:
"""Determine if end date input should be hidden for this event type"""
return event_type == "EZ pauschal"
@staticmethod
def get_event_type_description(event_type: str) -> str:
"""Get description for event type"""
descriptions = {
"EZ 100%": "Vollzeit Erziehungszeit - vollständige Unterbrechung der Arbeit",
"EZ 50%": "Teilzeit Erziehungszeit - 50% Arbeitszeit",
"EZ pauschal": "Pauschale Erziehungszeit - automatisch 2 Jahre",
"Sonstige": "Andere Ausfallzeiten wie Krankheit, Weiterbildung, etc."
}
return descriptions.get(event_type, "")
@staticmethod
def get_processing_order() -> List[str]:
"""Get the order in which event types should be processed"""
return ["EZ 100%", "EZ 50%", "EZ pauschal", "Sonstige"]
@staticmethod
def is_full_time_event(event_type: str) -> bool:
"""Check if event type represents full-time absence"""
return event_type in ["EZ 100%", "EZ pauschal"]
@staticmethod
def is_part_time_event(event_type: str) -> bool:
"""Check if event type represents part-time absence"""
return event_type == "EZ 50%"
@staticmethod
def is_other_event(event_type: str) -> bool:
"""Check if event type represents other absence"""
return event_type == "Sonstige"
|