Arbeitstagerkenung, Abwesenheitstage
Arbeitstagerkennung eingefügt Dialog für Abwesenheitstage braucht noch Logik für Rangeeintragungen
This commit is contained in:
parent
b3de2d2b9e
commit
9a4bf599dd
64
users.py
64
users.py
@ -7,6 +7,7 @@ import datetime
|
|||||||
import time
|
import time
|
||||||
import json
|
import json
|
||||||
import shutil
|
import shutil
|
||||||
|
import re
|
||||||
|
|
||||||
from definitions import userfolder, scriptpath, usersettingsfilename, photofilename, status_in, status_out
|
from definitions import userfolder, scriptpath, usersettingsfilename, photofilename, status_in, status_out
|
||||||
|
|
||||||
@ -32,18 +33,24 @@ class user:
|
|||||||
self.username = data["username"]
|
self.username = data["username"]
|
||||||
self.fullname = data["fullname"]
|
self.fullname = data["fullname"]
|
||||||
|
|
||||||
def get_stamp_file(self):
|
def get_stamp_file(self, time_stamp=None):
|
||||||
|
if time_stamp == None:
|
||||||
year = str(datetime.datetime.now().year)
|
year = str(datetime.datetime.now().year)
|
||||||
month = str(datetime.datetime.now().month)
|
month = str(datetime.datetime.now().month)
|
||||||
|
else:
|
||||||
|
year = str(datetime.datetime.fromtimestamp(time_stamp).year)
|
||||||
|
month = str(datetime.datetime.fromtimestamp(time_stamp).month)
|
||||||
completepath = f"{self.userfolder}/{year}-{month}"
|
completepath = f"{self.userfolder}/{year}-{month}"
|
||||||
return completepath
|
return completepath
|
||||||
|
|
||||||
def timestamp(self, stamptime=-1):
|
def timestamp(self, stamptime=-1):
|
||||||
filename = f"{self.get_stamp_file()}.txt"
|
|
||||||
if stamptime == -1:
|
if stamptime == -1:
|
||||||
stamptime = time.time()
|
stamptime = time.time()
|
||||||
timestamp = int(stamptime)
|
timestamp = int(stamptime)
|
||||||
|
|
||||||
|
filename = f"{self.get_stamp_file(time_stamp=stamptime)}.txt"
|
||||||
|
|
||||||
try:
|
try:
|
||||||
# Öffne die Datei im Anhang-Modus ('a')
|
# Öffne die Datei im Anhang-Modus ('a')
|
||||||
with open(filename, 'a') as file:
|
with open(filename, 'a') as file:
|
||||||
@ -142,6 +149,14 @@ class user:
|
|||||||
for i in range(int(self.get_starting_day()[0]), year_now + 1):
|
for i in range(int(self.get_starting_day()[0]), year_now + 1):
|
||||||
years.append(str(i))
|
years.append(str(i))
|
||||||
|
|
||||||
|
for file in os.listdir(self.userfolder):
|
||||||
|
if re.match(r"\d{4}-\d{1,2}\.json", file):
|
||||||
|
year = file.split("-")[0]
|
||||||
|
if year not in years:
|
||||||
|
years.append(year)
|
||||||
|
|
||||||
|
years.sort()
|
||||||
|
print(years)
|
||||||
return years
|
return years
|
||||||
|
|
||||||
def get_months(self, year):
|
def get_months(self, year):
|
||||||
@ -154,7 +169,7 @@ class user:
|
|||||||
month_now = int(datetime.datetime.now().month)
|
month_now = int(datetime.datetime.now().month)
|
||||||
|
|
||||||
if start_year == int(year):
|
if start_year == int(year):
|
||||||
print("Start_year is year")
|
|
||||||
if start_year == year_now:
|
if start_year == year_now:
|
||||||
for i in range(start_month, month_now + 1):
|
for i in range(start_month, month_now + 1):
|
||||||
available_months.append(i)
|
available_months.append(i)
|
||||||
@ -168,7 +183,15 @@ class user:
|
|||||||
elif int(year) < year_now:
|
elif int(year) < year_now:
|
||||||
for i in range(1, 13):
|
for i in range(1, 13):
|
||||||
available_months.append(i)
|
available_months.append(i)
|
||||||
|
print(available_months)
|
||||||
|
for file in os.listdir(self.userfolder):
|
||||||
|
|
||||||
|
if re.match(r"\d{4}-\d{1,2}\.json", file):
|
||||||
|
if file.split("-")[0] == str(year):
|
||||||
|
month = int(file.split("-")[1].split(".")[0])
|
||||||
|
if month not in available_months:
|
||||||
|
available_months.append(month)
|
||||||
|
available_months.sort()
|
||||||
return(available_months)
|
return(available_months)
|
||||||
|
|
||||||
def get_timestamps(self, year, month):
|
def get_timestamps(self, year, month):
|
||||||
@ -208,13 +231,44 @@ class user:
|
|||||||
|
|
||||||
def get_absence(self, year, month):
|
def get_absence(self, year, month):
|
||||||
try:
|
try:
|
||||||
print(f"{self.userfolder}/{year}-{month}.json")
|
|
||||||
with open(f"{self.userfolder}/{year}-{month}.json", "r") as json_file:
|
with open(f"{self.userfolder}/{year}-{month}.json", "r") as json_file:
|
||||||
json_data = json.load(json_file)
|
json_data = json.load(json_file)
|
||||||
absence = json_data["absence"]
|
absence = json_data["absence"]
|
||||||
return absence
|
return absence
|
||||||
except:
|
except:
|
||||||
return 0
|
return { }
|
||||||
|
|
||||||
|
def update_absence(self, year, month, day, absence_type):
|
||||||
|
try:
|
||||||
|
with open(f"{self.userfolder}/{int(year)}-{int(month)}.json", "r") as json_file:
|
||||||
|
json_data = json.load(json_file)
|
||||||
|
except:
|
||||||
|
with open(f"{self.userfolder}/{year}-{month}.json", "w") as json_file:
|
||||||
|
json_data = { }
|
||||||
|
json_data["archived"] = 0
|
||||||
|
json_data["overtime"] = 0
|
||||||
|
json_dict = json.dumps(json_data, indent=4)
|
||||||
|
json_file.write(json_dict)
|
||||||
|
try:
|
||||||
|
json_data["absence"][str(int(day))] = absence_type
|
||||||
|
except:
|
||||||
|
json_data.update({ "absence": { str(int(day)): absence_type}})
|
||||||
|
json_dict = json.dumps(json_data, indent=4)
|
||||||
|
print(json_dict)
|
||||||
|
print(f"{self.userfolder}/{year}-{month}.json")
|
||||||
|
|
||||||
|
with open(f"{self.userfolder}/{int(year)}-{int(month)}.json", "w") as json_file:
|
||||||
|
json_file.write(json_dict)
|
||||||
|
|
||||||
|
def del_absence(self, year, month, day):
|
||||||
|
with open(f"{self.userfolder}/{int(year)}-{int(month)}.json", "r") as json_file:
|
||||||
|
json_data = json.load(json_file)
|
||||||
|
|
||||||
|
del json_data["absence"][str(day)]
|
||||||
|
json_dict = json.dumps(json_data, indent=4)
|
||||||
|
|
||||||
|
with open(f"{self.userfolder}/{int(year)}-{int(month)}.json", "w") as json_file:
|
||||||
|
json_file.write(json_dict)
|
||||||
|
|
||||||
# Benutzer auflisten
|
# Benutzer auflisten
|
||||||
def list_users():
|
def list_users():
|
||||||
|
@ -26,3 +26,5 @@
|
|||||||
1745181050
|
1745181050
|
||||||
1745240760
|
1745240760
|
||||||
1745240762
|
1745240762
|
||||||
|
1740996000
|
||||||
|
1740997800
|
||||||
|
@ -1,12 +1,12 @@
|
|||||||
{
|
{
|
||||||
"archived": 0,
|
"archived": 0,
|
||||||
"total_hours": 0,
|
"overtime": 0,
|
||||||
"absence": {
|
"absence": {
|
||||||
"1": "U",
|
|
||||||
"4": "U",
|
|
||||||
"7": "K",
|
"7": "K",
|
||||||
"8": "UU",
|
"8": "UU",
|
||||||
"9": "KK",
|
"9": "KK",
|
||||||
"3": "K"
|
"10": "U",
|
||||||
|
"11": "U",
|
||||||
|
"29": "U"
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -1,7 +1,3 @@
|
|||||||
1743566400
|
|
||||||
1743606000
|
|
||||||
1743652800
|
|
||||||
1743660240
|
|
||||||
1744889948
|
1744889948
|
||||||
1744890300
|
1744890300
|
||||||
1744989797
|
1744989797
|
||||||
@ -18,8 +14,6 @@
|
|||||||
1744991473
|
1744991473
|
||||||
1744991477
|
1744991477
|
||||||
1744991770
|
1744991770
|
||||||
1745181046
|
|
||||||
1745181050
|
|
||||||
1745215200
|
1745215200
|
||||||
1745229600
|
1745229600
|
||||||
1745390818
|
1745390818
|
||||||
|
7
users/testuser1/2025-5.json
Normal file
7
users/testuser1/2025-5.json
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
{
|
||||||
|
"archived": 0,
|
||||||
|
"overtime": 0,
|
||||||
|
"absence": {
|
||||||
|
"14": "U"
|
||||||
|
}
|
||||||
|
}
|
7
users/testuser1/2026-4.json
Normal file
7
users/testuser1/2026-4.json
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
{
|
||||||
|
"archived": 0,
|
||||||
|
"overtime": 0,
|
||||||
|
"absence": {
|
||||||
|
"14": "F"
|
||||||
|
}
|
||||||
|
}
|
@ -3,7 +3,7 @@
|
|||||||
"fullname": "Pia Paulina",
|
"fullname": "Pia Paulina",
|
||||||
"password": "123456789",
|
"password": "123456789",
|
||||||
"workhours": {
|
"workhours": {
|
||||||
"2024-04-01": {
|
"2025-04-03": {
|
||||||
"1": "4",
|
"1": "4",
|
||||||
"2": "8",
|
"2": "8",
|
||||||
"3": "8",
|
"3": "8",
|
||||||
|
122
web_ui.py
122
web_ui.py
@ -136,21 +136,28 @@ def page_admin():
|
|||||||
def update_months():
|
def update_months():
|
||||||
current_user = user(time_user.value)
|
current_user = user(time_user.value)
|
||||||
available_months = current_user.get_months(year_binder.value)
|
available_months = current_user.get_months(year_binder.value)
|
||||||
available_months_dict = {}
|
available_months_dict = { }
|
||||||
|
|
||||||
for element in available_months:
|
for element in available_months:
|
||||||
available_months_dict[element] = calendar.month_name[int(element)]
|
available_months_dict[element] = calendar.month_name[int(element)]
|
||||||
print(available_months_dict)
|
|
||||||
select_month.clear()
|
select_month.clear()
|
||||||
select_month.set_options(available_months_dict)
|
select_month.set_options(available_months_dict)
|
||||||
select_month.value = list(available_months)[0]
|
select_month.value = list(available_months)[0]
|
||||||
|
|
||||||
|
def update_user():
|
||||||
|
current_user = user(time_user.value)
|
||||||
|
available_years = current_user.get_years()
|
||||||
|
select_year.clear()
|
||||||
|
select_year.set_options(available_years)
|
||||||
|
select_year.value = list(available_years)[0]
|
||||||
|
|
||||||
userlist = list_users()
|
userlist = list_users()
|
||||||
ui.markdown("Benutzer:")
|
ui.markdown("Benutzer:")
|
||||||
print("Time User wird konstruiert")
|
|
||||||
time_user = ui.select(options=userlist, value=userlist[0], on_change=update_months)
|
time_user = ui.select(options=userlist, value=userlist[0], on_change=update_user)
|
||||||
|
|
||||||
user_to_select_for_start = userlist[0]
|
user_to_select_for_start = userlist[0]
|
||||||
current_user = user(user_to_select_for_start)
|
|
||||||
|
|
||||||
current_year = datetime.datetime.now().year
|
current_year = datetime.datetime.now().year
|
||||||
current_month = datetime.datetime.now().month
|
current_month = datetime.datetime.now().month
|
||||||
@ -176,7 +183,7 @@ def page_admin():
|
|||||||
select_year = ui.select(options=available_years, value=set_year, on_change=update_months).bind_value_to(year_binder, 'value')
|
select_year = ui.select(options=available_years, value=set_year, on_change=update_months).bind_value_to(year_binder, 'value')
|
||||||
|
|
||||||
|
|
||||||
month_header = ui.markdown(f"###Buchungen für {current_user.fullname} für {calendar.month_name[int(select_month.value)]} {select_year.value}")
|
month_header = ui.markdown(f"###Buchungen für **{current_user.fullname}** für **{calendar.month_name[int(select_month.value)]} {select_year.value}**")
|
||||||
|
|
||||||
# Tabelle aufbauen
|
# Tabelle aufbauen
|
||||||
with ui.card() as calendar_card:
|
with ui.card() as calendar_card:
|
||||||
@ -215,13 +222,34 @@ def page_admin():
|
|||||||
# Buchungen
|
# Buchungen
|
||||||
|
|
||||||
with ui.row():
|
with ui.row():
|
||||||
|
def delete_absence(day, absence_type):
|
||||||
|
def execute_deletion():
|
||||||
|
current_user.del_absence(select_year.value, select_month.value, day)
|
||||||
|
calendar_card.clear()
|
||||||
|
update_month_and_year()
|
||||||
|
dialog.close()
|
||||||
|
ui.notify("Abwesenheitseintrag gelöscht")
|
||||||
|
with ui.dialog() as dialog, ui.card():
|
||||||
|
ui.markdown(f'''Soll der Eintrag **{absence_type}** für den **{day}. {calendar.month_name[int(select_month.value)]} {select_year.value}** gelöscht werden?
|
||||||
|
|
||||||
|
Dies kann nicht rückgägig gemacht werden!''')
|
||||||
|
with ui.grid(columns=3):
|
||||||
|
ui.button("Ja", on_click=execute_deletion)
|
||||||
|
ui.space()
|
||||||
|
ui.button("Nein", on_click=dialog.close)
|
||||||
|
dialog.open()
|
||||||
|
|
||||||
try:
|
try:
|
||||||
for i in list(user_absent):
|
for i in list(user_absent):
|
||||||
if int(i) == day:
|
if int(i) == day:
|
||||||
ui.button(absence_entries[user_absent[i]]["name"]).props(f'color={absence_entries[user_absent[i]]["color"]}')
|
ui.button(absence_entries[user_absent[i]]["name"], on_click=lambda i=i, day=day: delete_absence(day, absence_entries[user_absent[i]]["name"])).props(f'color={absence_entries[user_absent[i]]["color"]}')
|
||||||
except:
|
except:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
day_type = ui.markdown("Kein Arbeitstag")
|
||||||
|
day_type.set_visibility(False)
|
||||||
|
|
||||||
|
# Hier werden nur die Tage mit Timestamps behandelt
|
||||||
if len(timestamps_dict[day]) > 0:
|
if len(timestamps_dict[day]) > 0:
|
||||||
timestamps_dict[day].sort()
|
timestamps_dict[day].sort()
|
||||||
|
|
||||||
@ -279,7 +307,6 @@ def page_admin():
|
|||||||
ui.button("Abbrechen", on_click=edit_dialog.close)
|
ui.button("Abbrechen", on_click=edit_dialog.close)
|
||||||
|
|
||||||
edit_dialog.open()
|
edit_dialog.open()
|
||||||
|
|
||||||
for i in range(len(timestamps_dict[day])):
|
for i in range(len(timestamps_dict[day])):
|
||||||
try:
|
try:
|
||||||
temp_pair = [ timestamps_dict[day][i] , timestamps_dict[day][i+1] ]
|
temp_pair = [ timestamps_dict[day][i] , timestamps_dict[day][i+1] ]
|
||||||
@ -325,30 +352,47 @@ def page_admin():
|
|||||||
ui.markdown("Kein")
|
ui.markdown("Kein")
|
||||||
|
|
||||||
# Arbeitszeitsoll bestimmen
|
# Arbeitszeitsoll bestimmen
|
||||||
|
|
||||||
workhour_entries = list(current_user.workhours)
|
workhour_entries = list(current_user.workhours)
|
||||||
workhour_entries.sort()
|
workhour_entries.sort()
|
||||||
|
|
||||||
found_match = False
|
found_match = False
|
||||||
|
if day_in_list.timestamp() < datetime.datetime.strptime(workhour_entries[0],
|
||||||
|
'%Y-%m-%d').timestamp():
|
||||||
|
ui.markdown("n. a.")
|
||||||
|
day_type.set_content("*Noch kein Arbeitsverhältnis*")
|
||||||
|
day_type.set_visibility(True)
|
||||||
|
|
||||||
|
else:
|
||||||
for entry in reversed(workhour_entries):
|
for entry in reversed(workhour_entries):
|
||||||
|
|
||||||
if datetime.datetime.strptime(entry, '%Y-%m-%d').timestamp() < day_in_list.timestamp() and found_match == False:
|
if datetime.datetime.strptime(entry, '%Y-%m-%d').timestamp() <= day_in_list.timestamp() and found_match == False:
|
||||||
|
|
||||||
if int(day_in_list.strftime('%w')) == 0:
|
if int(day_in_list.strftime('%w')) == 0:
|
||||||
weekday_index = 7
|
weekday_index = 7
|
||||||
else:
|
else:
|
||||||
weekday_index = int(day_in_list.strftime('%w'))
|
weekday_index = int(day_in_list.strftime('%w'))
|
||||||
ui.markdown(f"{current_user.workhours[entry][str(weekday_index)]} h")
|
hours_to_work = current_user.workhours[entry][str(weekday_index)]
|
||||||
|
ui.markdown(f"{convert_seconds_to_hours(int(hours_to_work) * 3600)}")
|
||||||
|
if int(hours_to_work) == 0:
|
||||||
|
day_type.content = "**Kein Arbeitstag**"
|
||||||
|
day_type.set_visibility(True)
|
||||||
|
|
||||||
found_match = True
|
found_match = True
|
||||||
|
|
||||||
|
|
||||||
# Saldo für den Tag berechnen
|
# Saldo für den Tag berechnen
|
||||||
|
try:
|
||||||
if time.time() > day_in_list.timestamp():
|
if time.time() > day_in_list.timestamp():
|
||||||
|
|
||||||
time_duty = int(current_user.workhours[entry][str(weekday_index)]) * 3600
|
time_duty = int(current_user.workhours[entry][str(weekday_index)]) * 3600
|
||||||
|
|
||||||
|
|
||||||
saldo = int(time_sum) - int(time_duty)
|
saldo = int(time_sum) - int(time_duty)
|
||||||
# Nach Abwesenheitseinträgen suchen
|
# Nach Abwesenheitseinträgen suchen
|
||||||
try:
|
try:
|
||||||
for i in list(user_absent):
|
for i in list(user_absent):
|
||||||
if int(i) == day:
|
if int(i) == day and user_absent[i] != "UU":
|
||||||
saldo = 0
|
saldo = 0
|
||||||
except:
|
except:
|
||||||
pass
|
pass
|
||||||
@ -357,7 +401,8 @@ def page_admin():
|
|||||||
ui.markdown(convert_seconds_to_hours(saldo))
|
ui.markdown(convert_seconds_to_hours(saldo))
|
||||||
else:
|
else:
|
||||||
ui.markdown("-")
|
ui.markdown("-")
|
||||||
|
except:
|
||||||
|
ui.markdown("n. a.")
|
||||||
|
|
||||||
def add_entry(day):
|
def add_entry(day):
|
||||||
with ui.dialog() as add_dialog, ui.card():
|
with ui.dialog() as add_dialog, ui.card():
|
||||||
@ -369,8 +414,8 @@ def page_admin():
|
|||||||
ui.notify("Bitte eine Uhrzeit auswählen.")
|
ui.notify("Bitte eine Uhrzeit auswählen.")
|
||||||
return
|
return
|
||||||
|
|
||||||
new_time_stamp = datetime.datetime(int(select_year.value),
|
new_time_stamp = datetime.datetime(int(year_binder.value),
|
||||||
int(select_month.value), day,
|
int(month_binder.value), day,
|
||||||
int(input_time.value[:2]),
|
int(input_time.value[:2]),
|
||||||
int(input_time.value[-2:])).timestamp()
|
int(input_time.value[-2:])).timestamp()
|
||||||
current_user = user(time_user.value)
|
current_user = user(time_user.value)
|
||||||
@ -384,7 +429,54 @@ def page_admin():
|
|||||||
ui.space()
|
ui.space()
|
||||||
ui.button("Abbrechen", on_click=add_dialog.close)
|
ui.button("Abbrechen", on_click=add_dialog.close)
|
||||||
add_dialog.open()
|
add_dialog.open()
|
||||||
ui.button("Eintrag hinzufügen", on_click=lambda day=day: add_entry(day))
|
add_dialog.move(calendar_card)
|
||||||
|
|
||||||
|
def add_absence(absence_type, day):
|
||||||
|
with ui.dialog() as dialog, ui.card():
|
||||||
|
ui.markdown(f'Für welchen Zeitraum soll *{absence_entries[absence_type]["name"]}* eingetragen werden?')
|
||||||
|
absence_dates = ui.date().props('range')
|
||||||
|
if day < 10:
|
||||||
|
day = f"0{str(day)}"
|
||||||
|
else:
|
||||||
|
day = str(day)
|
||||||
|
if int(select_month.value) < 10:
|
||||||
|
month = f"0{select_month.value}"
|
||||||
|
else:
|
||||||
|
month = select_month.value
|
||||||
|
absence_dates.value = f"{select_year.value}-{month}-{day}"
|
||||||
|
|
||||||
|
def add_absence_save():
|
||||||
|
# Bei nur einem Datum, direkt schreiben
|
||||||
|
if isinstance(absence_dates.value, str):
|
||||||
|
absence_date = absence_dates.value.split("-")
|
||||||
|
current_user.update_absence(absence_date[0], absence_date[1], absence_date[2], absence_type)
|
||||||
|
calendar_card.clear()
|
||||||
|
update_month_and_year()
|
||||||
|
# Bei Zeitbereich, aufteilen
|
||||||
|
if isinstance(absence_dates, dict):
|
||||||
|
pass
|
||||||
|
|
||||||
|
dialog.close()
|
||||||
|
|
||||||
|
|
||||||
|
with ui.grid(columns=3):
|
||||||
|
ui.button("Speichern", on_click=add_absence_save)
|
||||||
|
ui.space()
|
||||||
|
ui.button("Abbrechen", on_click=dialog.close)
|
||||||
|
|
||||||
|
dialog.open()
|
||||||
|
dialog.move(calendar_card)
|
||||||
|
|
||||||
|
with ui.button(icon='menu'):
|
||||||
|
with ui.menu() as menu:
|
||||||
|
ui.menu_item("Zeiteintrag hinzufügen", lambda day=day: add_entry(day))
|
||||||
|
ui.separator()
|
||||||
|
for i in list(absence_entries):
|
||||||
|
menu_item = ui.menu_item(f"{absence_entries[i]['name']} eintragen", lambda absence_type=i, day=day: add_absence(absence_type, day))
|
||||||
|
if str(day) in list(user_absent):
|
||||||
|
menu_item.disable()
|
||||||
|
|
||||||
|
#ui.button("Eintrag hinzufügen", on_click=lambda day=day: add_entry(day))
|
||||||
|
|
||||||
#4x leer und dann Gesamtsaldo
|
#4x leer und dann Gesamtsaldo
|
||||||
for i in range(4):
|
for i in range(4):
|
||||||
|
Loading…
x
Reference in New Issue
Block a user