Merge branch 'rework_monatsanzeige' into web_ui
This commit is contained in:
commit
cf2e8e3ab9
674
admin.py
Normal file
674
admin.py
Normal file
@ -0,0 +1,674 @@
|
||||
from datetime import datetime
|
||||
|
||||
from nicegui import ui, app
|
||||
|
||||
from users import *
|
||||
from definitions import *
|
||||
from calendar import monthrange
|
||||
from web_ui import *
|
||||
|
||||
import hashlib
|
||||
import calendar
|
||||
import locale
|
||||
|
||||
@ui.page('/admin')
|
||||
def page_admin():
|
||||
ui.page_title(f"{app_title} {app_version}")
|
||||
data = load_adminsettings()
|
||||
active_login = cookie_hash(data["admin_user"], data["admin_password"])
|
||||
try:
|
||||
browser_cookie = app.storage.user['secret']
|
||||
except:
|
||||
browser_cookie = ""
|
||||
|
||||
# Adminseite
|
||||
if browser_cookie == active_login:
|
||||
pageheader("Administration")
|
||||
|
||||
def admin_logout():
|
||||
app.storage.user['secret'] = ""
|
||||
ui.navigate.to("/login")
|
||||
|
||||
ui.button("Logout", on_click=admin_logout)
|
||||
|
||||
with ui.tabs() as tabs:
|
||||
|
||||
time_overview = ui.tab('Zeitübersichten')
|
||||
admin_user = ui.tab('Admin Benutzer')
|
||||
users = ui.tab('Benutzer')
|
||||
settings = ui.tab('Einstellungen')
|
||||
|
||||
with ((ui.tab_panels(tabs, value=time_overview))):
|
||||
|
||||
with ui.tab_panel(time_overview):
|
||||
ui.markdown("##Übersichten")
|
||||
|
||||
# Tabelle konstruieren
|
||||
with ui.card():
|
||||
|
||||
with ui.row() as timetable_header:
|
||||
year_binder = ValueBinder()
|
||||
month_binder = ValueBinder()
|
||||
|
||||
def update_months():
|
||||
current_user = user(time_user.value)
|
||||
available_months = current_user.get_months(year_binder.value)
|
||||
available_months_dict = { }
|
||||
|
||||
for element in available_months:
|
||||
available_months_dict[element] = calendar.month_name[int(element)]
|
||||
|
||||
select_month.clear()
|
||||
select_month.set_options(available_months_dict)
|
||||
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()
|
||||
ui.markdown("Benutzer:")
|
||||
|
||||
time_user = ui.select(options=userlist, value=userlist[0], on_change=update_user)
|
||||
|
||||
user_to_select_for_start = userlist[0]
|
||||
|
||||
current_year = datetime.datetime.now().year
|
||||
current_month = datetime.datetime.now().month
|
||||
current_user = user(user_to_select_for_start)
|
||||
available_years = current_user.get_years()
|
||||
available_months = current_user.get_months(current_year)
|
||||
available_months_dict = { }
|
||||
|
||||
for element in available_months:
|
||||
available_months_dict[element] = calendar.month_name[int(element)]
|
||||
|
||||
if current_month in available_months:
|
||||
set_month = current_month
|
||||
else:
|
||||
set_month = available_months[0]
|
||||
|
||||
if str(current_year) in available_years:
|
||||
set_year = str(current_year)
|
||||
else:
|
||||
set_year = (available_years[0])
|
||||
|
||||
select_month = ui.select(options=available_months_dict, value=set_month).bind_value_to(month_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}**")
|
||||
|
||||
# Tabelle aufbauen
|
||||
with ui.card() as calendar_card:
|
||||
def update_month_and_year():
|
||||
|
||||
with ui.grid(columns='auto auto 1fr 1fr 1fr 1fr') as table_grid:
|
||||
ui.markdown("**Datum**")
|
||||
ui.markdown("**Buchungen**")
|
||||
ui.markdown("**Ist**")
|
||||
ui.markdown("**Soll**")
|
||||
ui.markdown("**Saldo**")
|
||||
ui.space()
|
||||
|
||||
current_user = user(time_user.value)
|
||||
timestamps = current_user.get_timestamps(year=select_year.value, month=select_month.value)
|
||||
user_absent = current_user.get_absence(year=select_year.value, month=select_month.value)
|
||||
# Dictionary für sortierte Timestamps
|
||||
timestamps_dict = { }
|
||||
# Dictionary mit zunächst leeren Tageinträgen befüllen
|
||||
for day in range(1, monthrange(int(select_year.value), int(select_month.value))[1] + 1):
|
||||
# Jeder Tag bekommt eine leere Liste
|
||||
timestamps_dict[day] = [ ]
|
||||
|
||||
# Alle Timestamps durchgehen und sie den Dictionaryeinträgen zuordnen:
|
||||
for stamp in timestamps:
|
||||
day_of_month_of_timestamp = int(datetime.datetime.fromtimestamp(int(stamp)).strftime("%-d"))
|
||||
timestamps_dict[day_of_month_of_timestamp].append(int(stamp))
|
||||
|
||||
general_saldo = 0
|
||||
|
||||
for day in list(timestamps_dict):
|
||||
# Datum für Tabelle konstruieren
|
||||
day_in_list = datetime.datetime(int(select_year.value), int(select_month.value), day)
|
||||
ui.markdown(f"{day_in_list.strftime('%a')}., {day}. {calendar.month_name[int(select_month.value)]}")
|
||||
|
||||
# Buchungen
|
||||
|
||||
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:
|
||||
for i in list(user_absent):
|
||||
if int(i) == day:
|
||||
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:
|
||||
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:
|
||||
timestamps_dict[day].sort()
|
||||
|
||||
def edit_entry(t_stamp, day):
|
||||
|
||||
with ui.dialog() as edit_dialog, ui.card():
|
||||
ui.markdown("###Eintrag bearbeiten")
|
||||
timestamp = datetime.datetime.fromtimestamp(int(t_stamp))
|
||||
input_time = ui.time().classes('w-full justify-center')
|
||||
|
||||
input_time.value = timestamp.strftime('%H:%M')
|
||||
|
||||
def save_entry(day):
|
||||
nonlocal t_stamp
|
||||
t_stamp = f"{t_stamp}\n"
|
||||
position = timestamps.index(t_stamp)
|
||||
new_time_stamp = datetime.datetime(int(select_year.value),
|
||||
int(select_month.value), day,
|
||||
int(input_time.value[:2]),
|
||||
int(input_time.value[-2:]))
|
||||
timestamps[position] = str(
|
||||
int(new_time_stamp.timestamp())) + "\n"
|
||||
|
||||
current_user = user(time_user.value)
|
||||
current_user.write_edited_timestamps(timestamps,
|
||||
select_year.value,
|
||||
select_month.value)
|
||||
edit_dialog.close()
|
||||
calendar_card.clear()
|
||||
update_month_and_year()
|
||||
month_header.set_content(
|
||||
f"###Buchungen für {calendar.month_name[int(select_month.value)]} {select_year.value}")
|
||||
ui.notify("Eintrag gespeichert")
|
||||
|
||||
def del_entry():
|
||||
nonlocal t_stamp
|
||||
t_stamp = f"{t_stamp}\n"
|
||||
timestamps.remove(t_stamp)
|
||||
timestamps.sort()
|
||||
current_user = user(time_user.value)
|
||||
current_user.write_edited_timestamps(timestamps,
|
||||
select_year.value,
|
||||
select_month.value)
|
||||
edit_dialog.close()
|
||||
calendar_card.clear()
|
||||
update_month_and_year()
|
||||
month_header.set_content(
|
||||
f"###Buchungen für {calendar.month_name[int(select_month.value)]} {select_year.value}")
|
||||
ui.notify("Eintrag gelöscht")
|
||||
|
||||
with ui.row():
|
||||
ui.button("Speichern",
|
||||
on_click=lambda day=day: save_entry(day))
|
||||
ui.button("Löschen", on_click=del_entry)
|
||||
ui.button("Abbrechen", on_click=edit_dialog.close)
|
||||
|
||||
edit_dialog.open()
|
||||
for i in range(len(timestamps_dict[day])):
|
||||
try:
|
||||
temp_pair = [ timestamps_dict[day][i] , timestamps_dict[day][i+1] ]
|
||||
with ui.card():
|
||||
with ui.row():
|
||||
for j in temp_pair:
|
||||
ui.button(datetime.datetime.fromtimestamp(int(j)).strftime('%H:%M'), on_click=lambda t_stamp=j, day=day: edit_entry(t_stamp, day))
|
||||
except:
|
||||
if len(timestamps_dict[day]) % 2 != 0:
|
||||
with ui.card():
|
||||
ui.button(datetime.datetime.fromtimestamp(int(timestamps_dict[day][i])).strftime('%H:%M'), on_click=lambda t_stamp=timestamps_dict[day][i], day=day: edit_entry(t_stamp, day))
|
||||
|
||||
# Arbeitszeit Ist bestimmen
|
||||
timestamps_of_this_day = []
|
||||
|
||||
# Suche mir alle timestamps für diesen Tag
|
||||
for i in timestamps:
|
||||
actual_timestamp = datetime.datetime.fromtimestamp(int(i))
|
||||
timestamp_day = actual_timestamp.strftime('%-d')
|
||||
|
||||
if int(timestamp_day) == int(day):
|
||||
timestamps_of_this_day.append(i)
|
||||
|
||||
timestamps_of_this_day.sort()
|
||||
time_sum = 0
|
||||
if len(timestamps_of_this_day) > 1:
|
||||
|
||||
if len(timestamps_of_this_day) % 2 == 0:
|
||||
for i in range(0, len(timestamps_of_this_day), 2):
|
||||
time_delta = int(
|
||||
timestamps_of_this_day[i + 1]) - int(
|
||||
timestamps_of_this_day[i])
|
||||
time_sum = time_sum + time_delta
|
||||
else:
|
||||
for i in range(0, len(timestamps_of_this_day) - 1, 2):
|
||||
time_delta = int(
|
||||
timestamps_of_this_day[i + 1]) - int(
|
||||
timestamps_of_this_day[i])
|
||||
time_sum = time_sum + time_delta
|
||||
|
||||
ui.markdown(convert_seconds_to_hours(time_sum))
|
||||
else:
|
||||
ui.markdown("Kein")
|
||||
|
||||
# Arbeitszeitsoll bestimmen
|
||||
|
||||
hours_to_work = int(current_user.get_day_workhours(select_year.value, select_month.value, day))
|
||||
if hours_to_work < 0:
|
||||
ui.space()
|
||||
else:
|
||||
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)
|
||||
|
||||
|
||||
|
||||
# Saldo für den Tag berechnen
|
||||
|
||||
if time.time() > day_in_list.timestamp():
|
||||
|
||||
time_duty = int(current_user.get_day_workhours(select_year.value, select_month.value, day)) * 3600
|
||||
if time_duty < 0:
|
||||
ui.space()
|
||||
else:
|
||||
saldo = int(time_sum) - int(time_duty)
|
||||
# Nach Abwesenheitseinträgen suchen
|
||||
try:
|
||||
for i in list(user_absent):
|
||||
if int(i) == day and user_absent[i] != "UU":
|
||||
saldo = 0
|
||||
except:
|
||||
pass
|
||||
|
||||
general_saldo = general_saldo + saldo
|
||||
ui.markdown(convert_seconds_to_hours(saldo))
|
||||
else:
|
||||
ui.markdown("-")
|
||||
|
||||
def add_entry(day):
|
||||
with ui.dialog() as add_dialog, ui.card():
|
||||
ui.markdown("###Eintrag hinzufügen")
|
||||
input_time = ui.time().classes('w-full justify-center')
|
||||
|
||||
def add_entry_save():
|
||||
if input_time.value == None:
|
||||
ui.notify("Bitte eine Uhrzeit auswählen.")
|
||||
return
|
||||
|
||||
new_time_stamp = datetime.datetime(int(year_binder.value),
|
||||
int(month_binder.value), day,
|
||||
int(input_time.value[:2]),
|
||||
int(input_time.value[-2:])).timestamp()
|
||||
current_user = user(time_user.value)
|
||||
current_user.timestamp(stamptime=int(new_time_stamp))
|
||||
calendar_card.clear()
|
||||
update_month_and_year()
|
||||
add_dialog.close()
|
||||
ui.notify("Eintrag hinzugefügt")
|
||||
with ui.grid(columns=3):
|
||||
ui.button("Speichern", on_click=add_entry_save)
|
||||
ui.space()
|
||||
ui.button("Abbrechen", on_click=add_dialog.close)
|
||||
add_dialog.open()
|
||||
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
|
||||
elif isinstance(absence_dates.value, dict):
|
||||
start_date = absence_dates.value["from"]
|
||||
end_date = absence_dates.value["to"]
|
||||
start_date = start_date.split("-")
|
||||
end_date = end_date.split("-")
|
||||
|
||||
start_year = int(start_date[0])
|
||||
end_year = int(end_date[0])
|
||||
start_month = int(start_date[1])
|
||||
end_month = int(end_date[1])
|
||||
start_day = int(start_date[2])
|
||||
end_day = int(end_date[2])
|
||||
|
||||
start_date = datetime.datetime(start_year, start_month, start_day)
|
||||
end_date = datetime.datetime(end_year, end_month, end_day)
|
||||
actual_date = start_date
|
||||
|
||||
while actual_date <= end_date:
|
||||
current_user.workhours
|
||||
current_user.update_absence(actual_date.year, actual_date.month, actual_date.day, absence_type)
|
||||
|
||||
actual_date = actual_date + datetime.timedelta(days=1)
|
||||
clear_card()
|
||||
ui.notify("Einträge vorgenomomen")
|
||||
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
|
||||
for i in range(4):
|
||||
ui.space()
|
||||
ui.markdown(f"{convert_seconds_to_hours(general_saldo)}")
|
||||
for i in range(4):
|
||||
ui.space()
|
||||
ui.markdown("Stunden aus Vormonat")
|
||||
last_months_overtime = current_user.get_last_months_overtime(select_year.value, select_month.value)
|
||||
ui.markdown(f"{convert_seconds_to_hours(last_months_overtime)}")
|
||||
for i in range(4):
|
||||
ui.space()
|
||||
ui.markdown("Gesamtsaldo")
|
||||
ui.markdown(f"**<ins>{convert_seconds_to_hours(general_saldo + last_months_overtime)}</ins>**")
|
||||
table_grid.move(calendar_card)
|
||||
update_month_and_year()
|
||||
|
||||
def clear_card():
|
||||
calendar_card.clear()
|
||||
update_month_and_year()
|
||||
current_user = user(time_user.value)
|
||||
month_header.set_content(f"###Buchungen für **{current_user.fullname}** für **{calendar.month_name[int(select_month.value)]} {select_year.value}**")
|
||||
|
||||
button_update = ui.button("Aktualisieren", on_click=clear_card)
|
||||
button_update.move(timetable_header)
|
||||
|
||||
|
||||
with ui.tab_panel(admin_user):
|
||||
with ui.grid(columns=2):
|
||||
def save_admin_settings():
|
||||
output_dict = { }
|
||||
output_dict["admin_user"] = admin_user.value
|
||||
output_dict["adnin_password"] = admin_password.value
|
||||
json_dict = json.dumps(output_dict, indent=4)
|
||||
with open(f"{scriptpath}/{usersettingsfilename}", "w") as outputfile:
|
||||
outputfile.write(json_dict)
|
||||
ui.notify("Einstellungen gespeichert")
|
||||
|
||||
|
||||
ui.label("Benutzername des Adminstrators")
|
||||
admin_user = ui.input()
|
||||
admin_user.value = data["admin_user"]
|
||||
ui.label("Passwort des Adminsistrators")
|
||||
admin_password = ui.input(password=True)
|
||||
admin_password.value = data["admin_password"]
|
||||
ui.button("Speichern", on_click=save_admin_settings)
|
||||
|
||||
with ui.tab_panel(users):
|
||||
ui.markdown("###Benutzerverwaltung")
|
||||
userlist = list_users()
|
||||
userlist.sort()
|
||||
workhours = [ ]
|
||||
with ui.row():
|
||||
def user_selection_changed():
|
||||
try:
|
||||
if user_selection.value != None:
|
||||
current_user = user(user_selection.value)
|
||||
username_input.value = current_user.username
|
||||
fullname_input.value = current_user.fullname
|
||||
password_input.value = current_user.password
|
||||
usersettingscard.visible = True
|
||||
|
||||
workhours_select.clear()
|
||||
workhour_list = list(current_user.workhours)
|
||||
workhour_list.sort()
|
||||
workhours_select.set_options(workhour_list)
|
||||
workhours_select.value = workhour_list[0]
|
||||
workinghourscard.visible = True
|
||||
except:
|
||||
pass
|
||||
|
||||
# workhours_selection_changed(list(current_user.workhours)[0])
|
||||
|
||||
def workhours_selection_changed():
|
||||
if workhours_select.value != None:
|
||||
current_user = user(user_selection.value)
|
||||
selected_workhours = current_user.workhours[workhours_select.value]
|
||||
|
||||
for key, hours in selected_workhours.items():
|
||||
try:
|
||||
days[int(key)-1].value = hours
|
||||
except:
|
||||
if key == 0:
|
||||
days[6].value = hours
|
||||
elif key == "vacation":
|
||||
vacation_input.value = hours
|
||||
|
||||
def save_user_settings():
|
||||
def save_settings():
|
||||
current_user = user(user_selection.value)
|
||||
current_user.username = username_input.value
|
||||
current_user.fullname = fullname_input.value
|
||||
current_user.password = password_input.value
|
||||
current_user.write_settings()
|
||||
userlist = list_users()
|
||||
userlist.sort()
|
||||
user_selection.clear()
|
||||
user_selection.set_options(userlist)
|
||||
user_selection.value = current_user.username
|
||||
dialog.close()
|
||||
ui.notify("Einstellungen gespeichert")
|
||||
|
||||
with ui.dialog() as dialog, ui.card():
|
||||
if user_selection.value != username_input.value:
|
||||
ui.markdown("**Benutzername wurde geändert.**")
|
||||
ui.markdown(f"Benutzerdaten werden in den neuen Ordner {username_input.value}")
|
||||
ui.markdown("Sollen die Einstellungen gespeichert werden?")
|
||||
with ui.row():
|
||||
ui.button("Speichern", on_click=save_settings)
|
||||
ui.button("Abbrechen", on_click=dialog.close)
|
||||
dialog.open()
|
||||
|
||||
def del_user():
|
||||
current_user = user(user_selection.value)
|
||||
|
||||
def del_definitely():
|
||||
current_user.del_user()
|
||||
userlist = list_users()
|
||||
userlist.sort()
|
||||
user_selection.clear()
|
||||
user_selection.set_options(userlist)
|
||||
user_selection.value = userlist[0]
|
||||
dialog.close()
|
||||
ui.notify("Benutzer gelöscht")
|
||||
|
||||
with ui.dialog() as dialog, ui.card():
|
||||
ui.markdown(f"Soll der Benutzer *{current_user.username}* gelöscht werden?")
|
||||
ui.markdown("**Dies kann nicht rückgängig gemacht werden?**")
|
||||
with ui.row():
|
||||
ui.button("Löschen", on_click=del_definitely)
|
||||
ui.button("Abbrechen", on_click=dialog.close)
|
||||
|
||||
dialog.open()
|
||||
|
||||
def save_workhours():
|
||||
def save_settings():
|
||||
current_user = user(user_selection.value)
|
||||
construct_dict = { }
|
||||
for i in range(7):
|
||||
if i < 7:
|
||||
construct_dict[i+1] = days[i].value
|
||||
elif i == 7:
|
||||
conctruct_dict[0] = days[i].value
|
||||
|
||||
construct_dict["vacation"] = vacation_input.value
|
||||
current_user.workhours[workhours_select.value] = construct_dict
|
||||
current_user.write_settings()
|
||||
dialog.close()
|
||||
ui.notify("Einstellungen gespeichert")
|
||||
|
||||
with ui.dialog() as dialog, ui.card():
|
||||
ui.markdown("Sollen die Änderungen an den Arbeitsstunden und/oder Urlaubstagen gespeichert werden?")
|
||||
with ui.row():
|
||||
ui.button("Speichern", on_click=save_settings)
|
||||
ui.button("Abrrechen", on_click=dialog.close)
|
||||
dialog.open()
|
||||
|
||||
def delete_workhour_entry():
|
||||
def delete_entry():
|
||||
current_user = user(user_selection.value)
|
||||
del current_user.workhours[workhours_select.value]
|
||||
current_user.write_settings()
|
||||
workhour_list = list(current_user.workhours)
|
||||
workhours_select.clear()
|
||||
workhours_select.set_options(workhour_list)
|
||||
workhours_select.set_value(workhour_list[-1])
|
||||
|
||||
#workhours_selection_changed(current_user.workhours[0])
|
||||
dialog.close()
|
||||
ui.notify("Eintrag gelöscht"
|
||||
"")
|
||||
with ui.dialog() as dialog, ui.card():
|
||||
current_user = user(user_selection.value)
|
||||
if len(current_user.workhours) > 1:
|
||||
ui.markdown(f"Soll der Eintrag *{workhours_select.value}* wirklich gelöscht werden?")
|
||||
ui.markdown("**Dies kann nicht rückgängig gemacht werden.**")
|
||||
with ui.row():
|
||||
ui.button("Löschen", on_click=delete_entry)
|
||||
ui.button("Abbrechen", on_click=dialog.close)
|
||||
else:
|
||||
ui.markdown("Es gibt nur einen Eintrag. Dieser kann nicht gelöscht werden.")
|
||||
ui.button("OK", on_click=dialog.close)
|
||||
dialog.open()
|
||||
|
||||
with ui.column():
|
||||
user_selection = ui.select(options=userlist, with_input=True, on_change=user_selection_changed)
|
||||
user_selection.value = userlist[0]
|
||||
ui.button("Neu")
|
||||
|
||||
with ui.column():
|
||||
with ui.card() as usersettingscard:
|
||||
ui.markdown("**Benutzereinstellungen**")
|
||||
with ui.grid(columns=2):
|
||||
|
||||
ui.label("Benutzername:")
|
||||
username_input = ui.input()
|
||||
ui.label("Voller Name:")
|
||||
fullname_input = ui.input()
|
||||
ui.label("Passwort")
|
||||
password_input = ui.input(password=True)
|
||||
with ui.grid(columns=2):
|
||||
ui.button("Speichern", on_click=save_user_settings)
|
||||
ui.button("Löschen", on_click=del_user)
|
||||
|
||||
with ui.card() as workinghourscard:
|
||||
workhours = []
|
||||
ui.markdown("**Arbeitszeiten**")
|
||||
|
||||
with ui.card():
|
||||
|
||||
def calculate_weekhours():
|
||||
sum = 0
|
||||
for i in range(7):
|
||||
try:
|
||||
sum = float(days[i].value) + sum
|
||||
except:
|
||||
pass
|
||||
workhours_sum.set_content(str(sum))
|
||||
|
||||
with ui.grid(columns=2):
|
||||
ui.markdown("gültig ab:")
|
||||
workhours_select = ui.select(options=workhours, on_change=workhours_selection_changed)
|
||||
|
||||
days = [ ]
|
||||
weekdays = ["Montag", "Dienstag", "Mittwoch", "Donnerstag", "Freitag", "Samstag", "Sonntag"]
|
||||
counter = 0
|
||||
for day in weekdays:
|
||||
ui.markdown(f"{day}:")
|
||||
days.append(ui.input(on_change=calculate_weekhours))
|
||||
counter = counter + 1
|
||||
ui.separator().classes('col-span-full')
|
||||
ui.markdown("**Summe:**")
|
||||
workhours_sum = ui.markdown()
|
||||
|
||||
with ui.card():
|
||||
with ui.grid(columns=2):
|
||||
ui.markdown("Urlaubstage")
|
||||
vacation_input = ui.input()
|
||||
with ui.row():
|
||||
ui.button("Speichern", on_click=save_workhours)
|
||||
ui.button("Löschen", on_click=delete_workhour_entry)
|
||||
def new_workhours_entry():
|
||||
current_user = user(user_selection.value)
|
||||
|
||||
def add_workhours_entry():
|
||||
workhours_dict = { }
|
||||
for i in range(7):
|
||||
workhours_dict[i] = 0
|
||||
workhours_dict["vacation"] = 0
|
||||
current_user.workhours[date_picker.value] = workhours_dict
|
||||
current_user.write_settings()
|
||||
|
||||
workhours_select.clear()
|
||||
workhours_list = list(current_user.workhours)
|
||||
workhours_list.sort()
|
||||
workhours_select.set_options(workhours_list)
|
||||
workhours_select.value = date_picker.value
|
||||
|
||||
dialog.close()
|
||||
ui.notify("Eintrag angelegt")
|
||||
|
||||
with ui.dialog() as dialog, ui.card():
|
||||
ui.markdown("Geben Sie das Gültigkeitsdatum an, ab wann die Einträge gültig sein sollen.")
|
||||
date_picker = ui.date()
|
||||
|
||||
with ui.row():
|
||||
ui.button("OK", on_click=add_workhours_entry)
|
||||
ui.button("Abbrechen", on_click=dialog.close)
|
||||
dialog.open()
|
||||
ui.button("Neu", on_click=new_workhours_entry)
|
||||
user_selection_changed()
|
||||
|
||||
# Alternativ zur Loginseite navigieren
|
||||
else:
|
||||
ui.navigate.to("/login")
|
@ -19,3 +19,16 @@ photofilename = "photo.jpg"
|
||||
|
||||
status_in = "eingestempelt"
|
||||
status_out = "ausgestempelt"
|
||||
|
||||
# Abesenheiten
|
||||
|
||||
absence_entries = {"U": { "name": "Urlaub",
|
||||
"color": "green"},
|
||||
"K": { "name": "Krankheit",
|
||||
"color": "red"},
|
||||
"KK": { "name": "Krankheit Kind",
|
||||
"color": "orange"},
|
||||
"UU": { "name": "Urlaub aus Überstunden",
|
||||
"color": "green"},
|
||||
"F": { "name": "Fortbildung",
|
||||
"color": "black"}}
|
||||
|
41
login.py
Normal file
41
login.py
Normal file
@ -0,0 +1,41 @@
|
||||
from datetime import datetime
|
||||
|
||||
from nicegui import ui, app
|
||||
from web_ui import *
|
||||
|
||||
from users import *
|
||||
from definitions import *
|
||||
from calendar import monthrange
|
||||
|
||||
import hashlib
|
||||
import calendar
|
||||
import locale
|
||||
|
||||
@ui.page('/login')
|
||||
def page_login():
|
||||
|
||||
# Settingsdatei einlesen
|
||||
data = load_adminsettings()
|
||||
|
||||
def login():
|
||||
nonlocal data
|
||||
|
||||
if username.value == data["admin_user"]:
|
||||
if password.value == data["admin_password"]:
|
||||
active_login = cookie_hash(data["admin_user"], data["admin_password"])
|
||||
app.storage.user['secret'] = active_login
|
||||
ui.navigate.to("/admin")
|
||||
else:
|
||||
ui.notify("Login fehlgeschlagen")
|
||||
|
||||
#ui.markdown(f"## {app_title} {app_version}")
|
||||
#ui.markdown("Bitte einloggen")
|
||||
|
||||
pageheader("Bitte einloggen:")
|
||||
|
||||
with ui.grid(columns=2):
|
||||
ui.markdown("Benutzer:")
|
||||
username = ui.input('Benutzername')
|
||||
ui.markdown("Passwort:")
|
||||
password = ui.input('Passwort', password=True)
|
||||
ui.button(text="Login", on_click=lambda: login())
|
7
main.py
7
main.py
@ -0,0 +1,7 @@
|
||||
from web_ui import *
|
||||
from admin import *
|
||||
from login import *
|
||||
from users import *
|
||||
from touchscreen import *
|
||||
|
||||
ui.run(port=8090, storage_secret="test")
|
57
touchscreen.py
Normal file
57
touchscreen.py
Normal file
@ -0,0 +1,57 @@
|
||||
from datetime import datetime
|
||||
|
||||
from nicegui import ui, app
|
||||
|
||||
from users import *
|
||||
from definitions import *
|
||||
from web_ui import *
|
||||
from calendar import monthrange
|
||||
|
||||
import hashlib
|
||||
import calendar
|
||||
import locale
|
||||
|
||||
@ui.page('/touchscreen')
|
||||
def page_touchscreen():
|
||||
|
||||
def button_click(name):
|
||||
nonlocal buttons
|
||||
current_user = user(name)
|
||||
current_user.timestamp()
|
||||
if current_user.stamp_status() == status_in:
|
||||
buttons[name].props('color=green')
|
||||
ui.notify(status_in)
|
||||
else:
|
||||
buttons[name].props('color=red')
|
||||
ui.notify(status_out)
|
||||
|
||||
pageheader("Bitte User auswählen:")
|
||||
|
||||
userlist = list_users()
|
||||
number_of_users = len(userlist)
|
||||
buttons = { }
|
||||
|
||||
if number_of_users > 5:
|
||||
number_of_columns = 5
|
||||
else:
|
||||
number_of_columns = number_of_users
|
||||
|
||||
|
||||
with ui.grid(columns=number_of_columns):
|
||||
for name in userlist:
|
||||
current_user = user(name)
|
||||
current_button = ui.button(on_click=lambda name=name: button_click(name))
|
||||
with current_button:
|
||||
try:
|
||||
with open(current_user.photofile, 'r') as file:
|
||||
pass
|
||||
file.close()
|
||||
ui.image(current_user.photofile)
|
||||
except:
|
||||
pass
|
||||
ui.label(current_user.fullname)
|
||||
if current_user.stamp_status() == status_in:
|
||||
current_button.props('color=green')
|
||||
else:
|
||||
current_button.props('color=red')
|
||||
buttons[name] = current_button
|
176
users.py
176
users.py
@ -7,6 +7,7 @@ import datetime
|
||||
import time
|
||||
import json
|
||||
import shutil
|
||||
import re
|
||||
|
||||
from definitions import userfolder, scriptpath, usersettingsfilename, photofilename, status_in, status_out
|
||||
|
||||
@ -32,18 +33,24 @@ class user:
|
||||
self.username = data["username"]
|
||||
self.fullname = data["fullname"]
|
||||
|
||||
def get_stamp_file(self):
|
||||
year = str(datetime.datetime.now().year)
|
||||
month = str(datetime.datetime.now().month)
|
||||
def get_stamp_file(self, time_stamp=None):
|
||||
if time_stamp == None:
|
||||
year = str(datetime.datetime.now().year)
|
||||
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}"
|
||||
return completepath
|
||||
|
||||
def timestamp(self, stamptime=-1):
|
||||
filename = f"{self.get_stamp_file()}.txt"
|
||||
|
||||
if stamptime == -1:
|
||||
stamptime = time.time()
|
||||
timestamp = int(stamptime)
|
||||
|
||||
filename = f"{self.get_stamp_file(time_stamp=stamptime)}.txt"
|
||||
|
||||
try:
|
||||
# Öffne die Datei im Anhang-Modus ('a')
|
||||
with open(filename, 'a') as file:
|
||||
@ -124,35 +131,78 @@ class user:
|
||||
def del_user(self):
|
||||
shutil.rmtree(self.userfolder)
|
||||
|
||||
def get_starting_day(self):
|
||||
starting_date = list(self.workhours)
|
||||
starting_date.sort()
|
||||
year = str(starting_date[0])[:4]
|
||||
month = str(starting_date[0])[5:7]
|
||||
day = str(starting_date[0])[8:10]
|
||||
|
||||
return (year, month, day)
|
||||
|
||||
def get_years(self):
|
||||
txtfiles = [ ]
|
||||
years = [ ]
|
||||
|
||||
# Aktuelles Jahr bestimmen
|
||||
year_now = int(datetime.datetime.fromtimestamp(time.time()).strftime('%Y'))
|
||||
|
||||
for i in range(int(self.get_starting_day()[0]), year_now + 1):
|
||||
years.append(str(i))
|
||||
|
||||
for file in os.listdir(self.userfolder):
|
||||
if file.endswith(".txt"):
|
||||
txtfiles.append(file)
|
||||
for i in range(len(txtfiles)):
|
||||
txtfiles[i] = txtfiles[i][:4]
|
||||
txtfiles = list(set(txtfiles))
|
||||
txtfiles.sort()
|
||||
return txtfiles
|
||||
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
|
||||
|
||||
def get_months(self, year):
|
||||
txtfiles = [ ]
|
||||
for file in os.listdir(self.userfolder):
|
||||
if file.endswith(".txt"):
|
||||
txtfiles.append(file)
|
||||
txtfiles.sort()
|
||||
available_months = [ ]
|
||||
|
||||
for entry in txtfiles:
|
||||
if entry[:4] == str(year):
|
||||
available_months.append(entry[5:-4])
|
||||
return available_months
|
||||
# Anfangsdatum bestimmen
|
||||
start_year = int(self.get_starting_day()[0])
|
||||
start_month = int(self.get_starting_day()[1])
|
||||
year_now = int(datetime.datetime.now().year)
|
||||
month_now = int(datetime.datetime.now().month)
|
||||
|
||||
if start_year == int(year):
|
||||
|
||||
if start_year == year_now:
|
||||
for i in range(start_month, month_now + 1):
|
||||
available_months.append(i)
|
||||
elif start_year < year_now:
|
||||
for i in range(start_month, 13):
|
||||
available_months.append(i)
|
||||
else:
|
||||
if int(year) == year_now:
|
||||
for i in range(1, month_now + 1):
|
||||
available_months.append(i)
|
||||
elif int(year) < year_now:
|
||||
for i in range(1, 13):
|
||||
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)
|
||||
|
||||
def get_timestamps(self, year, month):
|
||||
with open(f"{self.userfolder}/{year}-{month}.txt", "r") as file:
|
||||
timestamps = file.readlines()
|
||||
timestamps.sort()
|
||||
return timestamps
|
||||
try:
|
||||
with open(f"{self.userfolder}/{year}-{month}.txt", "r") as file:
|
||||
timestamps = file.readlines()
|
||||
timestamps.sort()
|
||||
return timestamps
|
||||
except:
|
||||
timestamps = [ ]
|
||||
return timestamps
|
||||
|
||||
def write_edited_timestamps(self, timestamps, year, month):
|
||||
with open(f"{self.userfolder}/{year}-{month}.txt", "w") as file:
|
||||
@ -161,6 +211,82 @@ class user:
|
||||
def archive_hours(self, year, month):
|
||||
pass
|
||||
|
||||
def get_last_months_overtime(self, year, month):
|
||||
try:
|
||||
if int(month) == 1:
|
||||
year = str(int(year) - 1)
|
||||
month = str(12)
|
||||
else:
|
||||
month = str(int(month) - 1)
|
||||
with open(f"{self.userfolder}/{year}-{month}.json", "r") as json_file:
|
||||
json_data = json.load(json_file)
|
||||
|
||||
if json_data["archived"] == 1:
|
||||
overtime = int(json_data["overtime"])
|
||||
return overtime
|
||||
else:
|
||||
return 0
|
||||
except:
|
||||
return 0
|
||||
|
||||
def get_absence(self, year, month):
|
||||
try:
|
||||
with open(f"{self.userfolder}/{year}-{month}.json", "r") as json_file:
|
||||
json_data = json.load(json_file)
|
||||
absence = json_data["absence"]
|
||||
return absence
|
||||
except:
|
||||
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)
|
||||
|
||||
def get_day_workhours(self, year, month, day):
|
||||
workhour_entries = list(self.workhours)
|
||||
workhour_entries.sort()
|
||||
day_to_check = datetime.datetime(int(year), int(month), int(day))
|
||||
|
||||
for entry in reversed(workhour_entries):
|
||||
entry_split = entry.split("-")
|
||||
entry_dt = datetime.datetime(int(entry_split[0]), int(entry_split[1]), int(entry_split[2]))
|
||||
if entry_dt <= day_to_check:
|
||||
weekday = day_to_check.strftime("%w")
|
||||
if int(weekday) == 0:
|
||||
weekday = str(7)
|
||||
hours_to_work = self.workhours[entry][weekday]
|
||||
else:
|
||||
# Wenn vor Einstellungsdatum -1 ausgeben
|
||||
hours_to_work = -1
|
||||
return hours_to_work
|
||||
|
||||
# Benutzer auflisten
|
||||
def list_users():
|
||||
|
@ -1,4 +1,4 @@
|
||||
{
|
||||
"archived": 1,
|
||||
"total_hours": 28
|
||||
"overtime": 3950
|
||||
}
|
@ -26,3 +26,5 @@
|
||||
1745181050
|
||||
1745240760
|
||||
1745240762
|
||||
1740996000
|
||||
1740997800
|
||||
|
9
users/testuser1/2025-4.json
Normal file
9
users/testuser1/2025-4.json
Normal file
@ -0,0 +1,9 @@
|
||||
{
|
||||
"archived": 0,
|
||||
"overtime": 0,
|
||||
"absence": {
|
||||
"7": "K",
|
||||
"8": "UU",
|
||||
"9": "KK"
|
||||
}
|
||||
}
|
@ -1,13 +1,5 @@
|
||||
1743562800
|
||||
1743566400
|
||||
1743584340
|
||||
1743606000
|
||||
1743652800
|
||||
1743660240
|
||||
1743667140
|
||||
1743685200
|
||||
1744889948
|
||||
1744889966
|
||||
1744890300
|
||||
1744989797
|
||||
1744989827
|
||||
1744989830
|
||||
@ -22,15 +14,9 @@
|
||||
1744991473
|
||||
1744991477
|
||||
1744991770
|
||||
1744991777
|
||||
1745181046
|
||||
1745181050
|
||||
1745240760
|
||||
1745215200
|
||||
1745229600
|
||||
1745390818
|
||||
1745390894
|
||||
1745390894
|
||||
1745391029
|
||||
1745391037
|
||||
1745391056
|
||||
1745391058
|
||||
1745391059
|
||||
|
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",
|
||||
"password": "123456789",
|
||||
"workhours": {
|
||||
"2024-04-01": {
|
||||
"2025-04-03": {
|
||||
"1": "4",
|
||||
"2": "8",
|
||||
"3": "8",
|
||||
|
@ -1,4 +1,7 @@
|
||||
{
|
||||
"archived": 0,
|
||||
"total_hours": 0
|
||||
"total_hours": 0,
|
||||
"absence": {
|
||||
"1": "U"
|
||||
}
|
||||
}
|
594
web_ui.py
594
web_ui.py
@ -1,4 +1,3 @@
|
||||
import datetime
|
||||
from datetime import datetime
|
||||
|
||||
from nicegui import ui, app
|
||||
@ -22,7 +21,7 @@ class pageheader:
|
||||
|
||||
class ValueBinder:
|
||||
def __init__(self):
|
||||
self.value_to_bind = ""
|
||||
self.value = ""
|
||||
|
||||
def cookie_hash(user, password):
|
||||
return hashlib.sha256(b"{user}{app.storage.user['id']}{password}").hexdigest()
|
||||
@ -63,595 +62,6 @@ def convert_seconds_to_hours(seconds):
|
||||
else:
|
||||
return(f"{hours}:{minutes}")
|
||||
|
||||
|
||||
@ui.page('/login')
|
||||
def page_login():
|
||||
|
||||
# Settingsdatei einlesen
|
||||
data = load_adminsettings()
|
||||
|
||||
def login():
|
||||
nonlocal data
|
||||
|
||||
if username.value == data["admin_user"]:
|
||||
if password.value == data["admin_password"]:
|
||||
active_login = cookie_hash(data["admin_user"], data["admin_password"])
|
||||
app.storage.user['secret'] = active_login
|
||||
ui.navigate.to("/admin")
|
||||
else:
|
||||
ui.notify("Login fehlgeschlagen")
|
||||
|
||||
#ui.markdown(f"## {app_title} {app_version}")
|
||||
#ui.markdown("Bitte einloggen")
|
||||
|
||||
pageheader("Bitte einloggen:")
|
||||
|
||||
with ui.grid(columns=2):
|
||||
ui.markdown("Benutzer:")
|
||||
username = ui.input('Benutzername')
|
||||
ui.markdown("Passwort:")
|
||||
password = ui.input('Passwort', password=True)
|
||||
ui.button(text="Login", on_click=lambda: login())
|
||||
|
||||
|
||||
@ui.page('/admin')
|
||||
def page_admin():
|
||||
data = load_adminsettings()
|
||||
active_login = cookie_hash(data["admin_user"], data["admin_password"])
|
||||
try:
|
||||
browser_cookie = app.storage.user['secret']
|
||||
except:
|
||||
browser_cookie = ""
|
||||
|
||||
# Adminseite
|
||||
if browser_cookie == active_login:
|
||||
pageheader("Administration")
|
||||
|
||||
def admin_logout():
|
||||
app.storage.user['secret'] = ""
|
||||
ui.navigate.to("/login")
|
||||
|
||||
ui.button("Logout", on_click=admin_logout)
|
||||
|
||||
with ui.tabs() as tabs:
|
||||
|
||||
time_overview = ui.tab('Zeitübersichten')
|
||||
admin_user = ui.tab('Admin Benutzer')
|
||||
users = ui.tab('Benutzer')
|
||||
settings = ui.tab('Einstellungen')
|
||||
|
||||
with (ui.tab_panels(tabs, value=time_overview)):
|
||||
|
||||
with ui.tab_panel(time_overview):
|
||||
ui.markdown("##Übersichten")
|
||||
|
||||
# Tabelle konstruieren
|
||||
with ui.card():
|
||||
|
||||
with ui.row() as timetable_header:
|
||||
year_binder = ValueBinder()
|
||||
month_binder = ValueBinder()
|
||||
|
||||
def update_months():
|
||||
try:
|
||||
current_user = user(time_user.value)
|
||||
available_months = current_user.get_months(year_binder.value_to_bind)
|
||||
available_months_dict = {}
|
||||
for element in available_months:
|
||||
available_months_dict[element] = calendar.month_name[int(element)]
|
||||
select_month.clear()
|
||||
select_month.set_options(available_months_dict)
|
||||
select_month.value = list(available_months)[0]
|
||||
except:
|
||||
pass
|
||||
|
||||
userlist = list_users()
|
||||
ui.markdown("Benutzer:")
|
||||
time_user = ui.select(options=userlist, on_change=update_months)
|
||||
|
||||
time_user.value = userlist[0]
|
||||
current_year = datetime.datetime.now().year
|
||||
current_month = datetime.datetime.now().month
|
||||
|
||||
current_user = user(time_user.value)
|
||||
available_years = current_user.get_years()
|
||||
available_months = current_user.get_months(current_year)
|
||||
|
||||
available_months_dict = { }
|
||||
for element in available_months:
|
||||
available_months_dict[element] = calendar.month_name[int(element)]
|
||||
|
||||
select_month = ui.select(options=available_months_dict).bind_value(month_binder, 'value_to_bind')
|
||||
|
||||
select_year = ui.select(options=available_years, on_change=update_months).bind_value(year_binder, 'value_to_bind')
|
||||
try:
|
||||
select_year.value = str(current_year)
|
||||
except:
|
||||
pass
|
||||
try:
|
||||
select_month.value = str(current_month)
|
||||
except:
|
||||
select_month.value = str(available_months[0])
|
||||
|
||||
month_header = ui.markdown(f"###Buchungen für {calendar.month_name[int(select_month.value)]} {select_year.value}")
|
||||
|
||||
# Tabelle aufbauen
|
||||
with ui.card() as calendar_card:
|
||||
def update_month_and_year():
|
||||
|
||||
with ui.grid(columns='auto auto 1fr 1fr 1fr 1fr') as table_grid:
|
||||
ui.markdown("**Datum**")
|
||||
ui.markdown("**Buchungen**")
|
||||
ui.markdown("**Soll**")
|
||||
ui.markdown("**Ist**")
|
||||
ui.markdown("**Saldo**")
|
||||
ui.space()
|
||||
|
||||
current_user = user(time_user.value)
|
||||
timestamps = current_user.get_timestamps(year=select_year.value, month=select_month.value)
|
||||
|
||||
general_saldo = 0
|
||||
|
||||
for day in range(1, monthrange(int(select_year.value), int(select_month.value))[1] + 1):
|
||||
day_in_list = datetime.datetime(int(select_year.value), int(select_month.value), day)
|
||||
|
||||
ui.markdown(f"{day_in_list.strftime('%a')}., {day}. {calendar.month_name[int(select_month.value)]}")
|
||||
|
||||
# Buchungen
|
||||
|
||||
with ui.row():
|
||||
counter = 0
|
||||
|
||||
for i in timestamps:
|
||||
actual_timestamp = datetime.datetime.fromtimestamp(int(i))
|
||||
timestamp_day = actual_timestamp.strftime('%-d')
|
||||
|
||||
if int(timestamp_day) == int(day):
|
||||
def edit_entry(t_stamp, day):
|
||||
with ui.dialog() as edit_dialog, ui.card():
|
||||
ui.markdown("###Eintrag bearbeiten")
|
||||
timestamp = datetime.datetime.fromtimestamp(int(t_stamp))
|
||||
input_time = ui.time().classes('w-full justify-center')
|
||||
input_time.value = timestamp.strftime('%H:%M')
|
||||
|
||||
def save_entry(day):
|
||||
|
||||
position = timestamps.index(t_stamp)
|
||||
new_time_stamp = datetime.datetime(int(select_year.value), int(select_month.value), day, int(input_time.value[:2]), int(input_time.value[-2:]))
|
||||
timestamps[position] = str(
|
||||
int(new_time_stamp.timestamp())) + "\n"
|
||||
# print(timestamps)
|
||||
current_user = user(time_user.value)
|
||||
current_user.write_edited_timestamps(timestamps, select_year.value, select_month.value)
|
||||
edit_dialog.close()
|
||||
calendar_card.clear()
|
||||
update_month_and_year()
|
||||
month_header.set_content(f"###Buchungen für {calendar.month_name[int(select_month.value)]} {select_year.value}")
|
||||
ui.notify("Eintrag gespeichert")
|
||||
|
||||
def del_entry():
|
||||
timestamps.remove(t_stamp)
|
||||
timestamps.sort()
|
||||
current_user = user(time_user.value)
|
||||
current_user.write_edited_timestamps(timestamps, select_year.value, select_month.value)
|
||||
edit_dialog.close()
|
||||
calendar_card.clear()
|
||||
update_month_and_year()
|
||||
month_header.set_content(f"###Buchungen für {calendar.month_name[int(select_month.value)]} {select_year.value}")
|
||||
ui.notify("Eintrag gelöscht")
|
||||
|
||||
with ui.row():
|
||||
ui.button("Speichern",
|
||||
on_click=lambda day=day: save_entry(day))
|
||||
ui.button("Löschen", on_click=del_entry)
|
||||
ui.button("Abbrechen", on_click=edit_dialog.close)
|
||||
|
||||
edit_dialog.open()
|
||||
counter += 1
|
||||
|
||||
ui.button(actual_timestamp.strftime('%H:%M'), on_click=lambda t_stamp=i, day=day: edit_entry(t_stamp, day))
|
||||
if counter % 2 != 0:
|
||||
ui.markdown("-")
|
||||
else:
|
||||
ui.markdown("|")
|
||||
|
||||
# Arbeitszeitsoll bestimmen
|
||||
workhour_entries = list(current_user.workhours)
|
||||
workhour_entries.sort()
|
||||
|
||||
found_match = False
|
||||
for entry in reversed(workhour_entries):
|
||||
|
||||
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:
|
||||
weekday_index = 7
|
||||
else:
|
||||
weekday_index = int(day_in_list.strftime('%w'))
|
||||
ui.markdown(f"{current_user.workhours[entry][str(weekday_index)]} h")
|
||||
found_match = True
|
||||
|
||||
# Arbeitszeit Ist bestimmen
|
||||
timestamps_of_this_day = [ ]
|
||||
|
||||
# Suche mir alle timestamps für diesen Tag
|
||||
for i in timestamps:
|
||||
actual_timestamp = datetime.datetime.fromtimestamp(int(i))
|
||||
timestamp_day = actual_timestamp.strftime('%-d')
|
||||
|
||||
if int(timestamp_day) == int(day):
|
||||
timestamps_of_this_day.append(i)
|
||||
|
||||
timestamps_of_this_day.sort()
|
||||
time_sum = 0
|
||||
if len(timestamps_of_this_day) > 1:
|
||||
|
||||
|
||||
if len(timestamps_of_this_day) % 2 == 0:
|
||||
for i in range(0, len(timestamps_of_this_day), 2):
|
||||
time_delta = int(timestamps_of_this_day[i+1]) - int(timestamps_of_this_day[i])
|
||||
time_sum = time_sum + time_delta
|
||||
else:
|
||||
for i in range(0, len(timestamps_of_this_day) - 1, 2):
|
||||
time_delta = int(timestamps_of_this_day[i+1]) - int(timestamps_of_this_day[i])
|
||||
time_sum = time_sum + time_delta
|
||||
|
||||
ui.markdown(convert_seconds_to_hours(time_sum))
|
||||
else:
|
||||
ui.markdown("Kein")
|
||||
|
||||
# Plus und Minuszeit für den Tag berechnen
|
||||
if time.time() > day_in_list.timestamp():
|
||||
time_duty = int(current_user.workhours[entry][str(weekday_index)]) * 3600
|
||||
|
||||
saldo = int(time_sum) - int(time_duty)
|
||||
general_saldo = general_saldo + saldo
|
||||
ui.markdown(convert_seconds_to_hours(saldo))
|
||||
else:
|
||||
ui.markdown("-")
|
||||
|
||||
|
||||
def add_entry(day):
|
||||
with ui.dialog() as add_dialog, ui.card():
|
||||
ui.markdown("###Eintrag hinzufügen")
|
||||
input_time = ui.time().classes('w-full justify-center')
|
||||
|
||||
def add_entry_save():
|
||||
if input_time.value == None:
|
||||
ui.notify("Bitte eine Uhrzeit auswählen.")
|
||||
return
|
||||
|
||||
new_time_stamp = datetime.datetime(int(select_year.value),
|
||||
int(select_month.value), day,
|
||||
int(input_time.value[:2]),
|
||||
int(input_time.value[-2:])).timestamp()
|
||||
current_user = user(time_user.value)
|
||||
current_user.timestamp(stamptime=int(new_time_stamp))
|
||||
calendar_card.clear()
|
||||
update_month_and_year()
|
||||
add_dialog.close()
|
||||
ui.notify("Eintrag hinzugefügt")
|
||||
with ui.grid(columns=3):
|
||||
ui.button("Speichern", on_click=add_entry_save)
|
||||
ui.space()
|
||||
ui.button("Abbrechen", on_click=add_dialog.close)
|
||||
add_dialog.open()
|
||||
ui.button("Eintrag hinzufügen", on_click=lambda day=day: add_entry(day))
|
||||
#4x leer und dann Gesamtsald
|
||||
for i in range(4):
|
||||
ui.space()
|
||||
ui.markdown(f"<ins>{convert_seconds_to_hours(general_saldo)}</ins>")
|
||||
table_grid.move(calendar_card)
|
||||
update_month_and_year()
|
||||
|
||||
def clear_card():
|
||||
calendar_card.clear()
|
||||
update_month_and_year()
|
||||
month_header.set_content(f"###Buchungen für {calendar.month_name[int(select_month.value)]} {select_year.value}")
|
||||
|
||||
button_update = ui.button("Aktualisieren", on_click=clear_card)
|
||||
button_update.move(timetable_header)
|
||||
|
||||
|
||||
with ui.tab_panel(admin_user):
|
||||
with ui.grid(columns=2):
|
||||
def save_admin_settings():
|
||||
output_dict = { }
|
||||
output_dict["admin_user"] = admin_user.value
|
||||
output_dict["adnin_password"] = admin_password.value
|
||||
json_dict = json.dumps(output_dict, indent=4)
|
||||
with open(f"{scriptpath}/{usersettingsfilename}", "w") as outputfile:
|
||||
outputfile.write(json_dict)
|
||||
ui.notify("Einstellungen gespeichert")
|
||||
|
||||
|
||||
ui.label("Benutzername des Adminstrators")
|
||||
admin_user = ui.input()
|
||||
admin_user.value = data["admin_user"]
|
||||
ui.label("Passwort des Adminsistrators")
|
||||
admin_password = ui.input(password=True)
|
||||
admin_password.value = data["admin_password"]
|
||||
ui.button("Speichern", on_click=save_admin_settings)
|
||||
|
||||
with ui.tab_panel(users):
|
||||
ui.markdown("###Benutzerverwaltung")
|
||||
userlist = list_users()
|
||||
userlist.sort()
|
||||
workhours = [ ]
|
||||
with ui.row():
|
||||
def user_selection_changed():
|
||||
try:
|
||||
if user_selection.value != None:
|
||||
current_user = user(user_selection.value)
|
||||
username_input.value = current_user.username
|
||||
fullname_input.value = current_user.fullname
|
||||
password_input.value = current_user.password
|
||||
usersettingscard.visible = True
|
||||
|
||||
workhours_select.clear()
|
||||
workhour_list = list(current_user.workhours)
|
||||
workhour_list.sort()
|
||||
workhours_select.set_options(workhour_list)
|
||||
workhours_select.value = workhour_list[0]
|
||||
workinghourscard.visible = True
|
||||
except:
|
||||
pass
|
||||
|
||||
# workhours_selection_changed(list(current_user.workhours)[0])
|
||||
|
||||
def workhours_selection_changed():
|
||||
if workhours_select.value != None:
|
||||
current_user = user(user_selection.value)
|
||||
selected_workhours = current_user.workhours[workhours_select.value]
|
||||
|
||||
for key, hours in selected_workhours.items():
|
||||
try:
|
||||
days[int(key)-1].value = hours
|
||||
except:
|
||||
if key == 0:
|
||||
days[6].value = hours
|
||||
elif key == "vacation":
|
||||
vacation_input.value = hours
|
||||
|
||||
def save_user_settings():
|
||||
def save_settings():
|
||||
current_user = user(user_selection.value)
|
||||
current_user.username = username_input.value
|
||||
current_user.fullname = fullname_input.value
|
||||
current_user.password = password_input.value
|
||||
current_user.write_settings()
|
||||
userlist = list_users()
|
||||
userlist.sort()
|
||||
user_selection.clear()
|
||||
user_selection.set_options(userlist)
|
||||
user_selection.value = current_user.username
|
||||
dialog.close()
|
||||
ui.notify("Einstellungen gespeichert")
|
||||
|
||||
with ui.dialog() as dialog, ui.card():
|
||||
if user_selection.value != username_input.value:
|
||||
ui.markdown("**Benutzername wurde geändert.**")
|
||||
ui.markdown(f"Benutzerdaten werden in den neuen Ordner {username_input.value}")
|
||||
ui.markdown("Sollen die Einstellungen gespeichert werden?")
|
||||
with ui.row():
|
||||
ui.button("Speichern", on_click=save_settings)
|
||||
ui.button("Abbrechen", on_click=dialog.close)
|
||||
dialog.open()
|
||||
|
||||
def del_user():
|
||||
current_user = user(user_selection.value)
|
||||
|
||||
def del_definitely():
|
||||
current_user.del_user()
|
||||
userlist = list_users()
|
||||
userlist.sort()
|
||||
user_selection.clear()
|
||||
user_selection.set_options(userlist)
|
||||
user_selection.value = userlist[0]
|
||||
dialog.close()
|
||||
ui.notify("Benutzer gelöscht")
|
||||
|
||||
with ui.dialog() as dialog, ui.card():
|
||||
ui.markdown(f"Soll der Benutzer *{current_user.username}* gelöscht werden?")
|
||||
ui.markdown("**Dies kann nicht rückgängig gemacht werden?**")
|
||||
with ui.row():
|
||||
ui.button("Löschen", on_click=del_definitely)
|
||||
ui.button("Abbrechen", on_click=dialog.close)
|
||||
|
||||
dialog.open()
|
||||
|
||||
def save_workhours():
|
||||
def save_settings():
|
||||
current_user = user(user_selection.value)
|
||||
construct_dict = { }
|
||||
for i in range(7):
|
||||
if i < 7:
|
||||
construct_dict[i+1] = days[i].value
|
||||
elif i == 7:
|
||||
conctruct_dict[0] = days[i].value
|
||||
|
||||
construct_dict["vacation"] = vacation_input.value
|
||||
current_user.workhours[workhours_select.value] = construct_dict
|
||||
current_user.write_settings()
|
||||
dialog.close()
|
||||
ui.notify("Einstellungen gespeichert")
|
||||
|
||||
with ui.dialog() as dialog, ui.card():
|
||||
ui.markdown("Sollen die Änderungen an den Arbeitsstunden und/oder Urlaubstagen gespeichert werden?")
|
||||
with ui.row():
|
||||
ui.button("Speichern", on_click=save_settings)
|
||||
ui.button("Abrrechen", on_click=dialog.close)
|
||||
dialog.open()
|
||||
|
||||
def delete_workhour_entry():
|
||||
def delete_entry():
|
||||
current_user = user(user_selection.value)
|
||||
del current_user.workhours[workhours_select.value]
|
||||
current_user.write_settings()
|
||||
workhour_list = list(current_user.workhours)
|
||||
workhours_select.clear()
|
||||
workhours_select.set_options(workhour_list)
|
||||
workhours_select.set_value(workhour_list[-1])
|
||||
|
||||
#workhours_selection_changed(current_user.workhours[0])
|
||||
dialog.close()
|
||||
ui.notify("Eintrag gelöscht"
|
||||
"")
|
||||
with ui.dialog() as dialog, ui.card():
|
||||
current_user = user(user_selection.value)
|
||||
if len(current_user.workhours) > 1:
|
||||
ui.markdown(f"Soll der Eintrag *{workhours_select.value}* wirklich gelöscht werden?")
|
||||
ui.markdown("**Dies kann nicht rückgängig gemacht werden.**")
|
||||
with ui.row():
|
||||
ui.button("Löschen", on_click=delete_entry)
|
||||
ui.button("Abbrechen", on_click=dialog.close)
|
||||
else:
|
||||
ui.markdown("Es gibt nur einen Eintrag. Dieser kann nicht gelöscht werden.")
|
||||
ui.button("OK", on_click=dialog.close)
|
||||
dialog.open()
|
||||
|
||||
with ui.column():
|
||||
user_selection = ui.select(options=userlist, with_input=True, on_change=user_selection_changed)
|
||||
user_selection.value = userlist[0]
|
||||
ui.button("Neu")
|
||||
|
||||
with ui.column():
|
||||
with ui.card() as usersettingscard:
|
||||
ui.markdown("**Benutzereinstellungen**")
|
||||
with ui.grid(columns=2):
|
||||
|
||||
ui.label("Benutzername:")
|
||||
username_input = ui.input()
|
||||
ui.label("Voller Name:")
|
||||
fullname_input = ui.input()
|
||||
ui.label("Passwort")
|
||||
password_input = ui.input(password=True)
|
||||
with ui.grid(columns=2):
|
||||
ui.button("Speichern", on_click=save_user_settings)
|
||||
ui.button("Löschen", on_click=del_user)
|
||||
|
||||
with ui.card() as workinghourscard:
|
||||
workhours = []
|
||||
ui.markdown("**Arbeitszeiten**")
|
||||
|
||||
with ui.card():
|
||||
|
||||
def calculate_weekhours():
|
||||
sum = 0
|
||||
for i in range(7):
|
||||
try:
|
||||
sum = float(days[i].value) + sum
|
||||
except:
|
||||
pass
|
||||
workhours_sum.set_content(str(sum))
|
||||
|
||||
with ui.grid(columns=2):
|
||||
ui.markdown("gültig ab:")
|
||||
workhours_select = ui.select(options=workhours, on_change=workhours_selection_changed)
|
||||
|
||||
days = [ ]
|
||||
weekdays = ["Montag", "Dienstag", "Mittwoch", "Donnerstag", "Freitag", "Samstag", "Sonntag"]
|
||||
counter = 0
|
||||
for day in weekdays:
|
||||
ui.markdown(f"{day}:")
|
||||
days.append(ui.input(on_change=calculate_weekhours))
|
||||
counter = counter + 1
|
||||
ui.separator().classes('col-span-full')
|
||||
ui.markdown("**Summe:**")
|
||||
workhours_sum = ui.markdown()
|
||||
|
||||
with ui.card():
|
||||
with ui.grid(columns=2):
|
||||
ui.markdown("Urlaubstage")
|
||||
vacation_input = ui.input()
|
||||
with ui.row():
|
||||
ui.button("Speichern", on_click=save_workhours)
|
||||
ui.button("Löschen", on_click=delete_workhour_entry)
|
||||
def new_workhours_entry():
|
||||
current_user = user(user_selection.value)
|
||||
|
||||
def add_workhours_entry():
|
||||
workhours_dict = { }
|
||||
for i in range(7):
|
||||
workhours_dict[i] = 0
|
||||
workhours_dict["vacation"] = 0
|
||||
current_user.workhours[date_picker.value] = workhours_dict
|
||||
current_user.write_settings()
|
||||
|
||||
workhours_select.clear()
|
||||
workhours_list = list(current_user.workhours)
|
||||
workhours_list.sort()
|
||||
workhours_select.set_options(workhours_list)
|
||||
workhours_select.value = date_picker.value
|
||||
|
||||
dialog.close()
|
||||
ui.notify("Eintrag angelegt")
|
||||
|
||||
with ui.dialog() as dialog, ui.card():
|
||||
ui.markdown("Geben Sie das Gültigkeitsdatum an, ab wann die Einträge gültig sein sollen.")
|
||||
date_picker = ui.date()
|
||||
|
||||
with ui.row():
|
||||
ui.button("OK", on_click=add_workhours_entry)
|
||||
ui.button("Abbrechen", on_click=dialog.close)
|
||||
dialog.open()
|
||||
ui.button("Neu", on_click=new_workhours_entry)
|
||||
user_selection_changed()
|
||||
|
||||
# Alternativ zur Loginseite navigieren
|
||||
else:
|
||||
ui.navigate.to("/login")
|
||||
|
||||
@ui.page('/stamping')
|
||||
def page_stamping():
|
||||
ui.label('Stempelsteite')
|
||||
|
||||
@ui.page('/touchscreen')
|
||||
def page_touchscreen():
|
||||
|
||||
def button_click(name):
|
||||
nonlocal buttons
|
||||
current_user = user(name)
|
||||
current_user.timestamp()
|
||||
if current_user.stamp_status() == status_in:
|
||||
buttons[name].props('color=green')
|
||||
ui.notify(status_in)
|
||||
else:
|
||||
buttons[name].props('color=red')
|
||||
ui.notify(status_out)
|
||||
|
||||
pageheader("Bitte User auswählen:")
|
||||
|
||||
userlist = list_users()
|
||||
number_of_users = len(userlist)
|
||||
buttons = { }
|
||||
|
||||
if number_of_users > 5:
|
||||
number_of_columns = 5
|
||||
else:
|
||||
number_of_columns = number_of_users
|
||||
|
||||
|
||||
with ui.grid(columns=number_of_columns):
|
||||
for name in userlist:
|
||||
current_user = user(name)
|
||||
current_button = ui.button(on_click=lambda name=name: button_click(name))
|
||||
with current_button:
|
||||
try:
|
||||
with open(current_user.photofile, 'r') as file:
|
||||
pass
|
||||
file.close()
|
||||
ui.image(current_user.photofile)
|
||||
except:
|
||||
pass
|
||||
ui.label(current_user.fullname)
|
||||
if current_user.stamp_status() == status_in:
|
||||
current_button.props('color=green')
|
||||
else:
|
||||
current_button.props('color=red')
|
||||
buttons[name] = current_button
|
||||
|
||||
|
||||
@ui.page('/userlist')
|
||||
def page_userlist():
|
||||
|
||||
@ -667,6 +77,4 @@ def page_userlist():
|
||||
button = ui.button(text=name, on_click=lambda name=name:click_button(name) )
|
||||
buttons[name] = button
|
||||
|
||||
ui.run(port=8090, storage_secret="test")
|
||||
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user