158 lines
5.2 KiB
Python
158 lines
5.2 KiB
Python
import re
|
|
from datetime import datetime, timedelta
|
|
import holidays
|
|
import calendar
|
|
import json
|
|
|
|
def timedelta_to_string(td: timedelta) -> str:
|
|
"""Convert a timedelta object to a string in the format HH:MM."""
|
|
|
|
total_minutes = int(td.total_seconds() / 60)
|
|
hours = abs(total_minutes) // 60
|
|
minutes = abs(total_minutes) % 60
|
|
sign = "-" if td.total_seconds() < 0 else ""
|
|
|
|
return f"{sign}{hours:02}:{minutes:02}"
|
|
|
|
def process_input_txt(text: str) -> list:
|
|
"""
|
|
Process text containing work records and return a sorted list of dictionaries
|
|
containing the extracted data.
|
|
|
|
Args:
|
|
text (str): Text containing work records.
|
|
|
|
Returns:
|
|
list[dict]: List of dictionaries containing the fields 'enter', 'exit', and 'duration'.
|
|
"""
|
|
pattern = re.compile(
|
|
r"""
|
|
(?P<name>\S+\s\S+)\s+ # Name
|
|
(?P<start_date>\d{2}\.\d{2}\.\d{4}\s\d{2}:\d{2}:\d{2})\s+ # Start date
|
|
(?P<end_date>\d{2}\.\d{2}\.\d{4}\s\d{2}:\d{2}:\d{2})\s+ # End date
|
|
(?P<duration>\d{2}:\d{2}) # Duration
|
|
""",
|
|
re.VERBOSE,
|
|
)
|
|
|
|
results = []
|
|
for line in text.splitlines():
|
|
line = line.strip()
|
|
if not line:
|
|
continue
|
|
match = pattern.match(line)
|
|
if match:
|
|
try:
|
|
start_date = datetime.strptime(match.group("start_date"), "%d.%m.%Y %H:%M:%S")
|
|
end_date = datetime.strptime(match.group("end_date"), "%d.%m.%Y %H:%M:%S")
|
|
duration = timedelta(
|
|
hours=int(match.group("duration")[:2]), minutes=int(match.group("duration")[3:])
|
|
)
|
|
results.append(
|
|
{
|
|
"enter": start_date,
|
|
"exit": end_date,
|
|
"duration": duration,
|
|
}
|
|
)
|
|
except ValueError:
|
|
# Ignore invalid dates
|
|
continue
|
|
|
|
# Sort results by start date
|
|
results.sort(key=lambda x: x["enter"])
|
|
return results
|
|
|
|
|
|
def generate_monthly_summary(work_records: list, year: int, month: int) -> list:
|
|
# Polska lista dni świątecznych
|
|
pl_holidays = holidays.Poland(years=year)
|
|
|
|
# Liczba dni w miesiącu
|
|
_, num_days = calendar.monthrange(year, month)
|
|
summary = []
|
|
|
|
# Oblicz godziny pracy na dzień (8h 15min = 8.25h)
|
|
daily_work_hours = timedelta(hours=8, minutes=15)
|
|
holiday_work_hours = timedelta(hours=0, minutes=15)
|
|
|
|
# Suma godzin oczekiwanych i rzeczywistych
|
|
total_expected = timedelta(0)
|
|
total_actual = timedelta(0)
|
|
|
|
# Tworzenie wpisów dla każdego dnia
|
|
for day in range(1, num_days + 1):
|
|
date = datetime(year, month, day)
|
|
weekday = date.weekday() # 0 = poniedziałek, ..., 6 = niedziela
|
|
is_holiday = date in pl_holidays
|
|
should_work = weekday < 5 and not is_holiday # Praca w dni robocze poza świętami
|
|
|
|
# Aktualizuj oczekiwany czas pracy
|
|
if should_work:
|
|
total_expected += daily_work_hours
|
|
|
|
# Znajdź godziny faktyczne dla tego dnia
|
|
daily_actual = sum(
|
|
(record["duration"]
|
|
for record in work_records
|
|
if record["enter"].date() == date.date()) , timedelta()
|
|
)
|
|
total_actual += daily_actual # Dodanie timedelta do sumy
|
|
|
|
# Dodaj dane do listy podsumowania
|
|
summary.append({
|
|
"day": date.date(),
|
|
"weekday": weekday,
|
|
"is_holiday": is_holiday,
|
|
"total_expected": timedelta_to_string(total_expected),
|
|
"total_actual": timedelta_to_string(total_actual),
|
|
"total_diffrance": timedelta_to_string(total_actual - total_expected),
|
|
"daily_actual": timedelta_to_string(daily_actual),
|
|
"daily_diffrance": timedelta_to_string(daily_actual - (daily_work_hours if should_work else holiday_work_hours if daily_actual >= holiday_work_hours else timedelta(0))),
|
|
})
|
|
|
|
return summary
|
|
|
|
# text3 = """
|
|
# Worked hours
|
|
|
|
# Attendance Reason
|
|
# Marcin Nowak 22.11.2024 07:12:30 22.11.2024 16:05:33 08:53
|
|
|
|
# Marcin Nowak 21.11.2024 07:25:38 21.11.2024 16:43:19 09:18
|
|
|
|
# Marcin Nowak 20.11.2024 07:31:46 20.11.2024 15:47:36 08:16
|
|
|
|
# Marcin Nowak 19.11.2024 07:10:39 19.11.2024 15:54:14 08:44
|
|
|
|
# Marcin Nowak 18.11.2024 07:13:11 18.11.2024 16:04:15 08:51
|
|
|
|
# Marcin Nowak 15.11.2024 07:06:31 15.11.2024 15:41:49 08:35
|
|
|
|
# Marcin Nowak 14.11.2024 06:56:23 14.11.2024 16:11:52 09:15
|
|
|
|
# Marcin Nowak 13.11.2024 07:12:25 13.11.2024 17:19:58 10:08
|
|
|
|
# Marcin Nowak 12.11.2024 07:40:57 12.11.2024 16:10:42 08:30
|
|
|
|
# Marcin Nowak 08.11.2024 07:01:22 08.11.2024 15:48:01 08:47
|
|
|
|
# Marcin Nowak 07.11.2024 07:07:53 07.11.2024 16:26:30 09:19
|
|
|
|
# Marcin Nowak 06.11.2024 07:11:46 06.11.2024 16:08:43 08:57
|
|
|
|
# Marcin Nowak 05.11.2024 07:16:33 05.11.2024 16:10:52 08:54
|
|
|
|
# Marcin Nowak 04.11.2024 07:28:10 04.11.2024 15:51:19 08:23
|
|
|
|
# """
|
|
|
|
# # Przetwórz dane wejściowe
|
|
# work_records = process_input_txt(text3)
|
|
# date = work_records[-1]["enter"].date()
|
|
# monthly_summary = generate_monthly_summary(work_records, date.year, date.month)
|
|
|
|
# # Przykład wyświetlenia podsumowania
|
|
# import pprint
|
|
# pprint.pprint(monthly_summary)
|