odoo_hours setup and ready
This commit is contained in:
157
app/odoo_hours/text_conv.py
Normal file
157
app/odoo_hours/text_conv.py
Normal file
@@ -0,0 +1,157 @@
|
||||
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)
|
||||
Reference in New Issue
Block a user