diff --git a/admin.py b/admin.py index 2de4ffc..b3dc822 100644 --- a/admin.py +++ b/admin.py @@ -112,344 +112,392 @@ def page_admin(): 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() - - + @ui.refreshable + def timetable(): + with ui.card() as calendar_card: + def update_month_and_year(): 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] = [ ] + # Archivstatus - # 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) - class_content = "" - if day_in_list.date() == datetime.datetime.now().date(): - class_content = 'font-bold text-red-700 uppercase' - ui.markdown(f"{day_in_list.strftime('%a')}., {day}. {calendar.month_name[int(select_month.value)]}").classes(class_content) - - # 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().props('format24h now-btn').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)).classes('text-right') + with ui.grid(columns='auto auto 1fr 1fr 1fr 1fr') as table_grid: + if int(select_month.value) > 1: + archive_status = current_user.get_archive_status(int(select_year.value), + int(select_month.value)) else: - ui.markdown("Kein") + archive_status = current_user.get_archive_status(int(select_year.value) - 1, 12) - # Arbeitszeitsoll bestimmen + def revoke_archive_status(): + def revoke_status(): + filename = f"{current_user.userfolder}/{int(select_year.value)}-{int(select_month.value)}.json" + with open(filename, 'r') as json_file: + data = json.load(json_file) + data["archived"] = 0 - 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)}").classes('text-right') - if int(hours_to_work) == 0: - day_type.content = "**Kein Arbeitstag**" - day_type.set_visibility(True) + json_dict = json.dumps(data) - if day_in_list.strftime("%Y-%m-%d") in data["holidays"]: - day_type.content = f'**{data["holidays"][day_in_list.strftime("%Y-%m-%d")]}**' + with open(filename, "w") as outputfile: + outputfile.write(json_dict) + timetable.refresh() + dialog.close() - # Saldo für den Tag berechnen + with ui.dialog() as dialog, ui.card(): + ui.label("Soll der Archivstatus für den aktuellen Monat aufgehoben werden, damit Änderungen vorgenommen werden können?") + with ui.grid(columns=2): + ui.button("Ja", on_click=revoke_status) + ui.button("Nein", on_click=dialog.close) + dialog.open() - if time.time() > day_in_list.timestamp(): + if archive_status: + with ui.row().classes('text-right col-span-6 justify-center'): + ui.button("Archiviert", on_click=revoke_archive_status).classes('bg-transparent text-black') + ui.separator() + calendar_card.classes('bg-yellow') + # Überschriften + ui.markdown("**Datum**") + ui.markdown("**Buchungen**") + ui.markdown("**Ist**") + ui.markdown("**Soll**") + ui.markdown("**Saldo**") + ui.space() + + 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) + class_content = "" + if day_in_list.date() == datetime.datetime.now().date(): + class_content = 'font-bold text-red-700 uppercase' + ui.markdown(f"{day_in_list.strftime('%a')}., {day}. {calendar.month_name[int(select_month.value)]}").classes(class_content) + + # 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() - 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 + if int(i) == day: + absence_button = 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"]}') + if archive_status: + absence_button.disable() except: pass - general_saldo = general_saldo + saldo - ui.markdown(convert_seconds_to_hours(saldo)).classes('text-right') - else: - ui.markdown("-").classes('text-center') + day_type = ui.markdown("Kein Arbeitstag") + day_type.set_visibility(False) - 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') + # Hier werden nur die Tage mit Timestamps behandelt + if len(timestamps_dict[day]) > 0: + timestamps_dict[day].sort() - def add_entry_save(): - if input_time.value == None: - ui.notify("Bitte eine Uhrzeit auswählen.") - return + def edit_entry(t_stamp, day): - 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) + with ui.dialog() as edit_dialog, ui.card(): + ui.markdown("**Eintrag bearbeiten**") + timestamp = datetime.datetime.fromtimestamp(int(t_stamp)) + input_time = ui.time().props('format24h now-btn').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().classes('bg-inherit'): + with ui.row(): + for j in temp_pair: + timestamp_button = ui.button(datetime.datetime.fromtimestamp(int(j)).strftime('%H:%M'), on_click=lambda t_stamp=j, day=day: edit_entry(t_stamp, day)) + if archive_status: + timestamp_button.disable() + except: + if len(timestamps_dict[day]) % 2 != 0: + with ui.card().classes('bg-inherit'): + timestamp_button = 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)) + if archive_status: + timestamp_button.disable() + + # 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)).classes('text-right') + 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)}").classes('text-right') + if int(hours_to_work) == 0: + day_type.content = "**Kein Arbeitstag**" + day_type.set_visibility(True) + + if day_in_list.strftime("%Y-%m-%d") in data["holidays"]: + day_type.content = f'**{data["holidays"][day_in_list.strftime("%Y-%m-%d")]}**' + + # 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() - 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().classes('w-[350px]'): - ui.markdown(f'Für welchen Zeitraum soll *{absence_entries[absence_type]["name"]}* eingetragen werden?').classes('w-full') - absence_dates = ui.date().props('range today-btn').classes('w-full justify-center') - absence_dates._props['locale'] = {'daysShort': ['Mo', 'Di', 'Mi', 'Do', 'Fr', 'Sa', 'So'], - 'months': ['Januar', 'Februar', 'März', 'April', 'Mai', 'Juni', 'Juli', 'August', 'September', 'Oktober', 'November', 'Dezember'], - 'monthsShort': ['Jan', 'Feb', 'Mär', 'Apr', 'Mai', 'Jun', 'Jul', 'Aug', 'Sep', 'Okt', 'Nov', 'Dez']} - absence_dates._props['title'] = absence_entries[absence_type]["name"] - absence_dates._props['minimal'] = True - - 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}" + 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 - 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) - current_sel_month = select_month.value - current_sel_year = select_year.value - update_user() - update_months() - select_year.value = current_sel_year - select_month.value = current_sel_month + general_saldo = general_saldo + saldo + ui.markdown(convert_seconds_to_hours(saldo)).classes('text-right') + else: + ui.markdown("-").classes('text-center') + + 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) - # 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("-") + def add_absence(absence_type, day): + with ui.dialog() as dialog, ui.card().classes('w-[350px]'): + ui.markdown(f'Für welchen Zeitraum soll *{absence_entries[absence_type]["name"]}* eingetragen werden?').classes('w-full') + absence_dates = ui.date().props('range today-btn').classes('w-full justify-center') + absence_dates._props['locale'] = {'daysShort': ['Mo', 'Di', 'Mi', 'Do', 'Fr', 'Sa', 'So'], + 'months': ['Januar', 'Februar', 'März', 'April', 'Mai', 'Juni', 'Juli', 'August', 'September', 'Oktober', 'November', 'Dezember'], + 'monthsShort': ['Jan', 'Feb', 'Mär', 'Apr', 'Mai', 'Jun', 'Jul', 'Aug', 'Sep', 'Okt', 'Nov', 'Dez']} + absence_dates._props['title'] = absence_entries[absence_type]["name"] + absence_dates._props['minimal'] = True - 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]) + 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}" - start_date = datetime.datetime(start_year, start_month, start_day) - end_date = datetime.datetime(end_year, end_month, end_day) - actual_date = start_date + 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) + current_sel_month = select_month.value + current_sel_year = select_year.value + update_user() + update_months() + select_year.value = current_sel_year + select_month.value = current_sel_month + calendar_card.clear() + update_month_and_year() - while actual_date <= end_date: - absences = current_user.get_absence(actual_date.year, actual_date.month) + # 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("-") - if str(actual_date.day) in list(absences): - current_user.del_absence(actual_date.year, actual_date.month, actual_date.day) - ui.notify(f"Eintrag {absence_entries[absences[str(actual_date.day)]]['name']} am {actual_date.day}.{actual_date.month}.{actual_date.year} überschrieben.") - current_user.update_absence(actual_date.year, actual_date.month, actual_date.day, absence_type) + 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]) - actual_date = actual_date + datetime.timedelta(days=1) - clear_card() - ui.notify("Einträge vorgenomomen") - dialog.close() + 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: + absences = current_user.get_absence(actual_date.year, actual_date.month) + + if str(actual_date.day) in list(absences): + current_user.del_absence(actual_date.year, actual_date.month, actual_date.day) + ui.notify(f"Eintrag {absence_entries[absences[str(actual_date.day)]]['name']} am {actual_date.day}.{actual_date.month}.{actual_date.year} überschrieben.") + 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).classes('w-full justify-center'): - ui.button("Speichern", on_click=add_absence_save) - ui.space() - ui.button("Abbrechen", on_click=dialog.close) + with ui.grid(columns=3).classes('w-full justify-center'): + ui.button("Speichern", on_click=add_absence_save) + ui.space() + ui.button("Abbrechen", on_click=dialog.close) - dialog.open() - dialog.move(calendar_card) + 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): + with ui.button(icon='menu'): + with ui.menu() as menu: + menu_item = ui.menu_item("Zeiteintrag hinzufügen", lambda day=day: add_entry(day)) + if archive_status: menu_item.disable() + 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 archive_status: + menu_item.disable() + if str(day) in list(user_absent): + menu_item.disable() - #ui.button("Eintrag hinzufügen", on_click=lambda day=day: add_entry(day)) + #ui.button("Eintrag hinzufügen", on_click=lambda day=day: add_entry(day)) - #4x leer und dann Gesamtsaldo - ui.space().classes('col-span-4') - ui.markdown(f"{convert_seconds_to_hours(general_saldo)}").classes('text-right') - ui.markdown("Stunden aus Vormonat").classes('col-span-4 text-right') - 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)}").classes('text-right') - ui.markdown("Gesamtsaldo").classes('col-span-4 text-right') - ui.markdown(f"**{convert_seconds_to_hours(general_saldo + last_months_overtime)}**").classes('text-right') - table_grid.move(calendar_card) - update_month_and_year() + #4x leer und dann Gesamtsaldo + ui.space().classes('col-span-4') + ui.markdown(f"{convert_seconds_to_hours(general_saldo)}").classes('text-right') + ui.markdown("Stunden aus Vormonat").classes('col-span-4 text-right') + 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)}").classes('text-right') + ui.markdown("Gesamtsaldo").classes('col-span-4 text-right') + ui.markdown(f"**{convert_seconds_to_hours(general_saldo + last_months_overtime)}**").classes('text-right') + + table_grid.move(calendar_card) - 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) + 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) + timetable() with ui.tab_panel(settings): with ui.card(): diff --git a/api.py b/api.py index 60634f9..a9d3020 100644 --- a/api.py +++ b/api.py @@ -22,8 +22,14 @@ def page_overview_month(username: str, year: int, month: int): try: current_user = user(username) ui.page_title(f"Bericht für {current_user.fullname} für {calendar.month_name[month]} {year}") - ui.label(datetime.now().strftime('%d.%m.%Y')).classes('absolute top-5 right-5') - ui.space() + if current_user.get_archive_status(year, month): + with ui.column().classes('w-full items-end gap-0'): + ui.label(f"Bericht erstellt am {datetime.now().strftime('%d.%m.%Y %H:%M:%S')}") + ui.label('Archiviert').classes('italic').classes('text-red text-bold text-xl') + #ui.add_head_html('') + else: + with ui.column().classes('w-full items-end gap-0'): + ui.label(f"Bericht erstellt am {datetime.now().strftime('%d.%m.%Y %H:%M:%S')}") ui.markdown(f'#Bericht für {current_user.fullname} für {calendar.month_name[month]} {year}') pad_x = 4 @@ -55,7 +61,11 @@ def page_overview_month(username: str, year: int, month: int): general_saldo = 0 - with ui.grid(columns='auto auto 1fr 1fr 1fr').classes(f'gap-0 border px-0 py-0'): + bg_color = '' + if current_user.get_archive_status(year, month): + bg_color = ' bg-yellow-100' + + with ui.grid(columns='auto auto 1fr 1fr 1fr').classes(f'gap-0 border px-0 py-0{bg_color}'): ui.markdown("**Datum**").classes(f'border px-{pad_x} py-{pad_y}') ui.markdown("**Buchungen**").classes(f'border px-{pad_x} py-{pad_y}') ui.markdown("**Ist**").classes(f'border px-{pad_x} py-{pad_y}') diff --git a/favicon.svg b/favicon.svg new file mode 100644 index 0000000..ecbb5e4 --- /dev/null +++ b/favicon.svg @@ -0,0 +1,118 @@ + + + + + + + + + + + + + + image/svg+xml + + + + + Openclipart + + + + + + + + + + + diff --git a/main.py b/main.py index 3da3f94..1b73ccf 100644 --- a/main.py +++ b/main.py @@ -22,7 +22,23 @@ def main(): homepage() - ui.run(port=port, storage_secret=secret, language='de-DE') + def startup_message(): + + message_string = f"{app_title} {app_version}" + underline = "" + for i in range(len(message_string)): + underline += "-" + print(message_string) + print(underline) + + url_string = "" + for i in list(app.urls): + url_string += f"{i}, " + url_string = url_string[0:-2] + print("Weboberfläche erreichbar unter: " + url_string) + + app.on_startup(startup_message) + ui.run(favicon="favicon.svg", port=port, storage_secret=secret, language='de-DE', show_welcome_message=False) if __name__ in ("__main__", "__mp_main__"): main() diff --git a/users/testuser1/2025-5.txt b/users/testuser1/2025-5.txt index ac88801..eb3add4 100644 --- a/users/testuser1/2025-5.txt +++ b/users/testuser1/2025-5.txt @@ -1,2 +1,2 @@ 1746385124 -1746385127 +1746388680 diff --git a/web_ui.py b/web_ui.py index c4b76e6..c1f4048 100644 --- a/web_ui.py +++ b/web_ui.py @@ -85,6 +85,9 @@ def convert_seconds_to_hours(seconds): remaining_seconds = remaining_seconds - minutes * 60 if remaining_seconds > 0 and sign != "-": minutes = minutes + 1 + if minutes == 60: + hours = hours + 1 + minutes = 0 if hours < 10: hours = "0" + str(hours) else: