Urlaubsanträge aus dem Frontend möglich

Zurückziehen von Urlaubsanträgen möglich
This commit is contained in:
Alexander Malzkuhn 2025-05-27 14:18:17 +02:00
parent 269e6985d0
commit 57eec6d4f1
8 changed files with 140 additions and 28 deletions

View File

@ -56,7 +56,7 @@ def page_admin():
update_userlist() update_userlist()
with (((ui.tab_panels(tabs, value=time_overview)))): with ui.tab_panels(tabs, value=time_overview):
with ui.tab_panel(time_overview): with ui.tab_panel(time_overview):
ui.markdown("##Übersichten") ui.markdown("##Übersichten")

View File

@ -17,6 +17,7 @@ backupfolder = str(os.path.join(scriptpath, "backup"))
usersettingsfilename = "settings.json" usersettingsfilename = "settings.json"
photofilename = "photo.jpg" photofilename = "photo.jpg"
va_file = "vacation_application.json"
# Status # Status

View File

@ -187,38 +187,89 @@ def homepage():
ui.separator() ui.separator()
with ui.grid(columns='1fr auto 1fr').classes('w-full justify-center'): with ui.tabs().classes('w-full items-center') as tabs:
overviews = ui.tab('Übersichten')
absence = ui.tab('Urlaubsantrag')
with ui.grid(columns='1fr auto 1fr').classes('w-full items-center'):
ui.space() ui.space()
with ui.tab_panels(tabs, value=overviews):
with ui.tab_panel(overviews):
def activate_vacation(): def activate_vacation():
binder_vacation.value = True binder_vacation.value = True
def activate_absence(): def activate_absence():
binder_absence.value = True binder_absence.value = True
with ui.grid(columns='1fr 1fr'): with ui.grid(columns='1fr 1fr'):
ui.markdown("**Monatsübersicht:**").classes('col-span-2') ui.markdown("**Monatsübersicht:**").classes('col-span-2')
month_year_select = ui.select(list(reversed(available_years)), label="Jahr", on_change=update_month).bind_value_to(binder_available_years, 'value') month_year_select = ui.select(list(reversed(available_years)), label="Jahr", on_change=update_month).bind_value_to(binder_available_years, 'value')
month_month_select = ui.select(available_months, label="Monat", on_change=enable_month) month_month_select = ui.select(available_months, label="Monat", on_change=enable_month)
month_month_select.disable() month_month_select.disable()
ui.space() ui.space()
month_button = ui.button("Anzeigen", on_click=lambda: ui.navigate.to(f"/api/month/{current_user.username}/{month_year_select.value}-{month_month_select.value}", new_tab=True)).bind_enabled_from(binder_month_button, 'value') month_button = ui.button("Anzeigen", on_click=lambda: ui.navigate.to(f"/api/month/{current_user.username}/{month_year_select.value}-{month_month_select.value}", new_tab=True)).bind_enabled_from(binder_month_button, 'value')
ui.markdown("**Urlaubsanspruch**").classes('col-span-2') ui.markdown("**Urlaubsanspruch**").classes('col-span-2')
vacation_select = ui.select(list(reversed(available_years)), on_change=activate_vacation) vacation_select = ui.select(list(reversed(available_years)), on_change=activate_vacation)
vacation_button = ui.button("Anzeigen", on_click=lambda: ui.navigate.to(f"/api/vacation/{current_user.username}/{vacation_select.value}", new_tab=True)).bind_enabled_from(binder_vacation, 'value') vacation_button = ui.button("Anzeigen", on_click=lambda: ui.navigate.to(f"/api/vacation/{current_user.username}/{vacation_select.value}", new_tab=True)).bind_enabled_from(binder_vacation, 'value')
ui.markdown("**Fehlzeitenübersicht**").classes('col-span-2') ui.markdown("**Fehlzeitenübersicht**").classes('col-span-2')
absences_select = ui.select(list(reversed(available_years)), on_change=activate_absence) absences_select = ui.select(list(reversed(available_years)), on_change=activate_absence)
absences_button = ui.button("Anzeigen", on_click=lambda: ui.navigate.to(f"api/absence/{current_user.username}/{absences_select.value}", new_tab=True)).bind_enabled_from(binder_absence, 'value') absences_button = ui.button("Anzeigen", on_click=lambda: ui.navigate.to(f"api/absence/{current_user.username}/{absences_select.value}", new_tab=True)).bind_enabled_from(binder_absence, 'value')
ui.separator().classes('col-span-2') ui.separator().classes('col-span-2')
def logout(): def logout():
app.storage.user.pop("active_user", None) app.storage.user.pop("active_user", None)
ui.navigate.to("/") ui.navigate.to("/")
ui.button("Logout", on_click=logout).classes('col-span-2') ui.button("Logout", on_click=logout).classes('col-span-2')
with ui.tab_panel(absence):
ui.label("Urlaub für folgenden Zeitraum beantragen:")
vacation_date = ui.date().props('range today-btn')
def vacation_submission():
try:
current_user.vacation_application(vacation_date.value["from"], vacation_date.value["to"])
except TypeError:
current_user.vacation_application(vacation_date.value, vacation_date.value)
vacation_date.value = ""
with ui.dialog() as dialog, ui.card():
ui.label("Urlaubsantrag wurde abgeschickt")
ui.button("OK", on_click=dialog.close)
open_vacation_applications.refresh()
dialog.open()
ui.button("Einreichen", on_click=vacation_submission).classes('w-full items-center').tooltip("Hiermit reichen Sie einen Urlaubsantrag für den oben markierten Zeitraum ein.")
@ui.refreshable
def open_vacation_applications():
open_applications = current_user.get_open_vacation_applications()
if len(list(open_applications)) > 0:
ui.separator()
ui.label("Offene Urlaubsanträge:").classes('font-bold')
va_columns = [ {'label': 'Index', 'name': 'index', 'field': 'index', 'classes': 'hidden', 'headerClasses': 'hidden'},
{'label': 'Start', 'name': 'start', 'field': 'start'},
{'label': 'Ende', 'name': 'end', 'field': 'end'}]
va_rows = [ ]
date_string = '%d.%m.%Y'
for i, dates in open_applications.items():
startdate_dt = datetime.datetime.strptime(dates[0], '%Y-%m-%d')
enddate_dt = datetime.datetime.strptime(dates[1], '%Y-%m-%d')
va_rows.append({'index': i, 'start': startdate_dt.strftime(date_string), 'end': enddate_dt.strftime(date_string)})
va_table = ui.table(columns=va_columns, rows=va_rows, selection="single", row_key="index").classes('w-full')
def retract_va():
try:
current_user.revoke_vacation_application(va_table.selected[0]["index"])
open_vacation_applications.refresh()
ui.notify("Urlaubsantrag zurückgezogen")
except IndexError:
ui.notify("Kein Urlaubsanstrag ausgewählt")
ui.button("Zurückziehen", on_click=retract_va).tooltip("Hiermit wird der oben gewählte Urlaubsantrag zurückgezogen.").classes('w-full')
open_vacation_applications()
ui.space() ui.space()
else: else:

View File

@ -11,7 +11,9 @@ import json
import shutil import shutil
import re import re
from lib.definitions import userfolder, scriptpath, usersettingsfilename, photofilename, status_in, status_out, standard_adminsettings, standard_usersettings from lib.definitions import userfolder, scriptpath, usersettingsfilename, photofilename, status_in, status_out, \
standard_adminsettings, standard_usersettings, va_file
# Benutzerklasse # Benutzerklasse
@ -451,6 +453,39 @@ class user:
return [total_time, in_time_stamp] return [total_time, in_time_stamp]
def vacation_application(self, startdate, enddate):
application_file = os.path.join(self.userfolder, va_file)
try:
with open(application_file, 'r') as json_file:
applications = json.load(json_file)
except FileNotFoundError:
applications = { }
applications[str(len(list(applications)))] = (startdate, enddate)
with open(application_file, 'w') as json_file:
json_file.write(json.dumps(applications, indent=4))
def get_open_vacation_applications(self):
application_file = os.path.join(self.userfolder, va_file)
try:
with open(application_file, 'r') as json_file:
applications = json.load(json_file)
except FileNotFoundError:
applications = { }
return applications
def revoke_vacation_application(self, index):
application_file = os.path.join(self.userfolder, va_file)
with open(application_file, 'r') as json_file:
applications = json.load(json_file)
del(applications[index])
new_applications = { }
new_index = 0
for index, dates in applications.items():
new_applications[new_index] = dates
new_index += 1
with open(application_file, 'w') as json_file:
json_file.write(json.dumps(new_applications, indent=4))
# Benutzer auflisten # Benutzer auflisten
def list_users(): def list_users():

View File

@ -0,0 +1 @@
{}

View File

@ -1,8 +1,7 @@
{ {
"username": "testuser10", "username": "testuser10",
"fullname": "Diego Dieci", "fullname": "Diego Dieci",
"password": "123456789", "password": "9f86d081884c7d659a2feaa0c55ad015a3bf4f1b2b0b822cd15d6c15b0f00a08",
"api_key": "807518cd5bd85c1e4855d340f9b77b23eac21b7f",
"workhours": { "workhours": {
"2024-04-01": { "2024-04-01": {
"1": "1", "1": "1",
@ -14,5 +13,6 @@
"7": "7", "7": "7",
"vacation": "30" "vacation": "30"
} }
} },
"api_key": "807518cd5bd85c1e4855d340f9b77b23eac21b7f"
} }

View File

@ -0,0 +1,6 @@
{
"0": [
"2025-06-09",
"2025-06-19"
]
}

View File

@ -0,0 +1,18 @@
{
"username": "testuser2",
"fullname": "testuser2",
"password": "37a8eec1ce19687d132fe29051dca629d164e2c4958ba141d5f4133a33f0688f",
"api_key": "84799b1cbb92514f047bc2186cb4b4aafb352d69",
"workhours": {
"2025-05-27": {
"1": 0,
"2": 0,
"3": 0,
"4": 0,
"5": 0,
"6": 0,
"7": 0,
"vacation": 0
}
}
}