from django.shortcuts import render, redirect from django.contrib.auth.decorators import login_required from django.http import JsonResponse from .models import Workday, Breaks, FreeDays, AbsenceReason, Absence from django.utils import timezone import requests, csv, os from django.templatetags.static import static from django.conf import settings from datetime import date from django.contrib.auth.models import User from calendar import monthrange import datetime import calendar from .forms import AddAbsence, ConfirmAbsenceForm from django.contrib import messages from users.models import UserFullName, UserYearAbsenceInfo from users.models import UserTime from datetime import timedelta from django.db.models.signals import post_save from users.signals import save_newabsence # Load freedays def loadingFreeDays(plz): # Getting land file_path = os.path.join(settings.STATIC_ROOT, 'users/extra/plz_short.csv') land = False with open(file_path, 'rt') as csvfile: filecsv = csv.reader(csvfile, delimiter=';') for row in filecsv: if row[1] == plz: land = row[6] break; if(land != False): # CALCULATE FREEDAYS AS JSON year = today = date.today().year URL = "https://feiertage-api.de/api/" PARAMS = {'jahr':year,'nur_land':land} r = requests.get(url = URL, params = PARAMS) return r.json() else: return False def get_datetime_range(year, month): nb_days = monthrange(year, month)[1] return [datetime.date(year, month, day) for day in range(1, nb_days+1)] @login_required def AbsenceManagmenet(request, activemonth=False, activeyear=False): # NEW ABSENCE if(request.method == "POST"): ''' Nachdem eine neue Abwesenheit gespeichert wurde, geht es zur normalen Seite zurück, jedoch mit den Daten des aktuell angezeigten Monate/Jahr ''' if(request.POST.get("form_type") == "absenceform"): formtocheck = AddAbsence(request.POST, instance=request.user) if(formtocheck.is_valid()): try: workinguser = UserFullName.objects.get(pk=formtocheck.cleaned_data["userid"]) # DIFFERENT USER AGENCY if(workinguser.profile.agency != request.user.profile.agency): messages.success(request, f'Das dürfen Sie nicht!') return redirect('tma-management', formtocheck.cleaned_data['activemonth'], formtocheck.cleaned_data['activeyear']) # ALL OK - START SAVING ABSENCE else: confirmstat = 0 if(request.user.has_perm("users.absencemanager") == False): confirmstat = 1 messages.success(request, f'Abwesenheit beantragt') # SEND NOTIFICATION else: messages.success(request, f'Abwesenheit eingetragen') rep = None if(formtocheck.cleaned_data["representator"] != None): rep = User.objects.get(pk=formtocheck.cleaned_data["representator"].pk) newab = Absence(agency=request.user.profile.agency, user=workinguser, start=formtocheck.cleaned_data["start"],end=formtocheck.cleaned_data["end"], representator=rep, confirm_status=confirmstat, info=formtocheck.cleaned_data["info"], reason=formtocheck.cleaned_data["reason"], start_ishalf=formtocheck.cleaned_data["start_ishalf"], end_ishalf=formtocheck.cleaned_data["end_ishalf"]).save() # USER NOT FOUND except: messages.success(request, f'Fehler bei Benutzerzuweisung!') return redirect('tma-management', formtocheck.cleaned_data['activemonth'], formtocheck.cleaned_data['activeyear']) return redirect('tma-management', formtocheck.cleaned_data['activemonth'], formtocheck.cleaned_data['activeyear']) else: messages.success(request, f'Fehler beim eintragen der neuen Abwesenheit!') return redirect('tma-management', formtocheck.cleaned_data['activemonth'], formtocheck.cleaned_data['activeyear']) else: return redirect('tma-management') # NORMAL VIEW else: prevmonth = "" nextmonth = "" #MONTH if(not activemonth or activemonth > 12 or activemonth < 1): activemonth = int(activemonth) #Active month activemonth=date.today().month if(activemonth == 1): prevmonth = 12 else: prevmonth = activemonth-1 if(activemonth == 12): nextmonth = 1 else: nextmonth = activemonth + 1 else: if(activemonth == 1): prevmonth = 12 else: prevmonth = activemonth-1 if(activemonth == 12): nextmonth = 1 else: nextmonth = activemonth + 1 #YEAR nextyear = date.today().year prevyear = date.today().year if(not activeyear): activeyear = date.today().year else: if(nextmonth == 1): nextyear = activeyear + 1 else: nextyear = activeyear if(prevmonth == 12): prevyear = activeyear - 1 else: prevyear = activeyear missinguserdata = [] #CHECK, ob alle nötigen Infos zur Urlaubsberechnung vorliegen for user in User.objects.filter(profile__agency=request.user.profile.agency): tempTime = UserTime.objects.get(user=user) if(tempTime.startdate == None): missinguserdata.append(user) kontingent = 0 inuse = 0 yearinfo = False try: yearinfo = list(UserYearAbsenceInfo.objects.filter(year=activeyear, user=request.user))[0] inuse = yearinfo.days_inuse kontingent = yearinfo.days - inuse except: pass context = { "active_link" : "abscence", "usersofagency" : User.objects.filter(profile__agency=request.user.profile.agency).order_by("-last_name"), "days_this_month" : get_datetime_range(activeyear,activemonth), "nextmonth" : nextmonth, "missinguserdata" : missinguserdata, "prevmonth" : prevmonth, "nextyear" : nextyear, "prevyear" : prevyear, "activemonth" : activemonth, "activeyear" : activeyear, "inuse" : inuse, "yearinfo" : yearinfo, "kontingent" : kontingent, "abscenceform" : AddAbsence(instance=request.user), "userown" : Absence.objects.filter(agency=request.user.profile.agency, user=request.user).order_by("-start") } if(request.user.has_perm("users.absencemanager")): context.update({ "needtoconfirm" : Absence.objects.filter(agency=request.user.profile.agency, confirm_status=1).order_by("-start"), "allabsences" : Absence.objects.filter(agency=request.user.profile.agency).order_by("-start") }) return render(request, 'timemanagement/tm_ab_management.html', context) @login_required def TimeManagement(request): context = { "active_link" : "timemanagement", "workdays" : Workday.objects.filter(agency=request.user.profile.agency, user=request.user).order_by("-start") } return render(request, 'timemanagement/timemanagement_management.html', context) @login_required def TimeAjax(request): data = {} if request.method == "GET": # START WORKDAY if request.GET["action"] == "start_day": wd = Workday(user=request.user, agency=request.user.profile.agency, start=timezone.now()) wd.save() data = { "success" : True, "wd_starttime" : wd.start.strftime("%H:%M:%S"), "wd_starttime_complete" : wd.start } # END DAY elif request.GET["action"] == "end_day": wd = list(Workday.objects.filter(user=request.user, agency=request.user.profile.agency, end=None))[0] # END ALL BREAKS for b in wd.breaks.all(): if b.end == None: b.end = timezone.now() b.save() wd.end = timezone.now() wd.save() breaksum = 0 for b in wd.breaks.all(): if(b.end != None): breaksum += (b.end - b.start).seconds data = { "success" : True, "wd_endtime" : wd.end.strftime("%H:%M:%S"), "actualbreaktime" : breaksum*1000 } # START A BREAK elif request.GET["action"] == "start_break": wd = list(Workday.objects.filter(user=request.user, agency=request.user.profile.agency, end=None))[0] newbreak = Breaks(workday=wd, user=request.user, agency=request.user.profile.agency, start=timezone.now()) newbreak.save() wd.breaks.add(newbreak) data = { "success" : True, "break_starttime" : newbreak.start, } # END BREAK elif request.GET["action"] == "end_break": wd = list(Workday.objects.filter(user=request.user, agency=request.user.profile.agency, end=None))[0] toendbreak = list(wd.breaks.filter(end=None))[0] toendbreak.end = timezone.now() toendbreak.save() wd = list(Workday.objects.filter(user=request.user, agency=request.user.profile.agency, end=None))[0] breaksum = 0 for b in wd.breaks.all(): if(b.end != None): breaksum += (b.end - b.start).seconds data = { "success" : True, "actualbreaktime" : breaksum*1000 } # REMOVE WORKDAY elif request.GET["action"] == "remove_workday": wd = Workday.objects.get(pk=request.GET.get("workday")) if(wd.user == request.user and wd.agency == request.user.profile.agency): wd.delete() data = { "success" : True } else: data = { "success" : False} # Get Rendered Table elif request.GET["action"] == "getrenderedtable": prevmonth = "" nextmonth = "" activemonth = int(request.GET["activemonth"]) activeyear = int(request.GET["activeyear"]) #MONTH if(not activemonth or activemonth > 12 or activemonth < 1): activemonth = int(activemonth) #Active month activemonth=date.today().month if(activemonth == 1): prevmonth = 12 else: prevmonth = activemonth-1 if(activemonth == 12): nextmonth = 1 else: nextmonth = activemonth + 1 else: if(activemonth == 1): prevmonth = 12 else: prevmonth = activemonth-1 if(activemonth == 12): nextmonth = 1 else: nextmonth = activemonth + 1 #YEAR nextyear = date.today().year prevyear = date.today().year if(not activeyear): activeyear = date.today().year else: if(nextmonth == 1): nextyear = activeyear + 1 else: nextyear = activeyear if(prevmonth == 12): prevyear = activeyear - 1 else: prevyear = activeyear missinguserdata = [] #CHECK, ob alle nötigen Infos zur Urlaubsberechnung vorliegen for user in User.objects.filter(profile__agency=request.user.profile.agency): tempTime = UserTime.objects.get(user=user) if(tempTime.startdate == None): missinguserdata.append(user) context = { "active_link" : "abscence", "usersofagency" : User.objects.filter(profile__agency=request.user.profile.agency).order_by("-last_name"), "days_this_month" : get_datetime_range(activeyear,activemonth), "activemonth" : activemonth, "missinguserdata" : missinguserdata, "activeyear" : activeyear, "nextmonth" : nextmonth, "prevmonth" : prevmonth, "nextyear" : nextyear, "prevyear" : prevyear } return render(request, "timemanagement/rendered_table.html", context) # Get Rendered Table elif request.GET["action"] == "checkrequired": reason = AbsenceReason.objects.get(pk=request.GET["rid"]) if(reason.agency == request.user.profile.agency): data = { "success" : True, "isreq" : reason.need_rep, "isholiday" : reason.is_holiday } else: data = { "success" : False } # DELETE ABSENCE elif request.GET["action"] == "remove_absence": absence = Absence.objects.get(pk=request.GET["ab"]) if(request.user.has_perm("users.absencemanager") and absence.agency == request.user.profile.agency): absence.delete() data = { "success" : True } # GET FORM FOR CONFIRM ABSENCE elif request.GET["action"] == "getrenderedform": context = { "confirmform" : ConfirmAbsenceForm(instance=request.user), "absence" : Absence.objects.get(pk=request.GET["abscenceid"]) } return render(request, "timemanagement/rendered_confirmform.html", context) elif request.GET["action"] == "confirmornotabscence": absence = Absence.objects.get(pk=request.GET["absencetowork"]) new_stat = request.GET["newconfstat"] info = request.GET["info"] if(absence.user.profile.agency == request.user.profile.agency and request.user.has_perm("users.absencemanager")): absence.confirm_status = new_stat absence.confirm_info = info post_save.disconnect(save_newabsence, sender=Absence) absence.save() post_save.connect(save_newabsence, sender=Absence) messages.success(request, f'Abwesenheit gespeichert!') else: messages.success(request, f'Das dürfen Sie nicht!') data = { "success" : True, "activemonth" : request.GET["activemonth"], "activeyear" : request.GET["activeyear"] } elif request.GET["action"] == "getrestholidays": user = User.objects.get(pk=request.GET["userid"]) usertimedata = UserTime.objects.get(user=user) today = date.today() if(user.profile.agency == request.user.profile.agency): start_day = request.GET["startdate"].split("__") start_day_obj = datetime.date(int(start_day[0]), int(start_day[1]), int(start_day[2])) end_day = request.GET["enddate"].split("__") end_day_obj = datetime.date(int(end_day[0]), int(end_day[1]), int(end_day[2])) try: holidayloose_date = datetime.date(start_day_obj.year, int(usertimedata.loose_holidedate.split(".")[1]), int(usertimedata.loose_holidedate.split(".")[0])) except: holidayloose_date = datetime.date(2020, int(usertimedata.loose_holidedate.split(".")[1]), int(usertimedata.loose_holidedate.split(".")[0])) start_half = True if request.GET["start_half"] == "false": start_half = False end_half = True if request.GET["end_half"] == "false": end_half = False choosenyear = int(start_day[0]) yeardata = list(UserYearAbsenceInfo.objects.filter(user=user, agency=user.profile.agency, year=choosenyear))[0] holiday_thisyear = 0 holiday_lastyear = yeardata.restdays holiday_nextyear = 0 try: holiday_nextyear = list(UserYearAbsenceInfo.objects.filter(user=user, agency=user.profile.agency, year=choosenyear+1))[0].days - list(UserYearAbsenceInfo.objects.filter(user=user, agency=user.profile.agency, year=choosenyear+1))[0].days_inuse except: holiday_nextyear = yeardata.days # Urlaub innerhalb eines Jahres inkl. Prüfung auf Resturlaubsanspruch if(end_day_obj.year == start_day_obj.year): # Startt des Urlaubs NACH Verfallsdatum - nur aktuelles JAhr und die Zahl interessiert if(start_day_obj > holidayloose_date): need_days = (calculateHolidays(request, start_day_obj, end_day_obj, start_half, end_half))*(-1) holiday_thisyear = yeardata.days - yeardata.days_inuse - need_days else: need_days = (calculateHolidays(request, start_day_obj, end_day_obj, start_half, end_half))*(-1) # Kein Resturlaub if(yeardata.restdays == 0.0): holiday_thisyear = yeardata.days - yeardata.days_inuse - need_days # Resturlaub vorhanden, berechne mit Resturlaub else: holiday_lastyear = yeardata.restdays holiday_thisyear = yeardata.days - yeardata.days_inuse temp_holiday = holiday_lastyear - need_days if(temp_holiday < 0): holiday_lastyear = 0 holiday_thisyear = yeardata.days - yeardata.days_inuse + temp_holiday else: holiday_lastyear = yeardata.restdays - need_days # Urlaub geht über das nächstes Jahr hinweg else: holiday_lastyear = yeardata.restdays date_splitter = datetime.date(end_day_obj.year, 1, 1) #days_next_year = end_day_obj - date_splitter_postyear #days_this_year = date_splitter_preyear - start_day_obj need_days = (calculateHolidays(request, start_day_obj, date_splitter, start_half, False))*(-1) + (calculateHolidays(request, date_splitter, end_day_obj, False, end_half))*(-1) holiday_thisyear = yeardata.days - yeardata.days_inuse - (calculateHolidays(request, start_day_obj, date_splitter, start_half, False))*(-1) holiday_nextyear = holiday_nextyear - (calculateHolidays(request, date_splitter, end_day_obj, False, end_half))*(-1) data = { "restholiday_thisyear" : holiday_thisyear, "restholiday_lastyear" : holiday_lastyear, "restholiday_nextyear" : holiday_nextyear, "need_days" : need_days } # REQUEST USER NO RIGHTS else: data = { "success" : False } # GET REQUEST ACTION UNKNOWN else: data = { "success" : False } return JsonResponse(data) ''' Gibt einen Integer zurück, welcher die Urlaubstage von Start zu Enddatum auf der Grundlage von Freitagen berechnet. Berücksichtigt sowohl Wochenende als auch in der Agentur hinterlegte Freitage/Schließtage ''' @login_required def calculateHolidays(request, start, end, start_half, end_half): restdays = 0 allfreedays = FreeDays.objects.filter(agency=request.user.profile.agency) if(end == start): if(start_half): return restdays - 0.5 else: return restdays - 1 else: if(end < start): return False else: counter = 0 if(start_half): counter -= 0.5 if(end_half): counter -= 0.5 weekdays = [6,7] freedaycounter = 0 for dt in daterange(start, end): if dt.isoweekday() not in weekdays: counter += 1 for freeday in allfreedays.all(): if(dt == freeday.day): freedaycounter += 1 return restdays - counter + freedaycounter @login_required def calculatingHolidaysByAbsence(request, absence): # Freitage laden, die innerhalb der gewünschten Abwesenheit liegen allfreedays = FreeDays.objects.filter(agency=request.user.profile.agency, day__gt=absence.start, day__lt=absence.end) finalholidayinabsence = 0 # Start und Ende gleich, nur ein Tag. Checken, ob Halber Tag if(absence.start == absence.end): if(absence.start_ishalf): finalholidayinabsence = 0.5 else: finalholidayinabsence = 1 return finalholidayinabsence else: if(absence.start_ishalf): finalholidayinabsence -= 0.5 if(absence.end_ishalf): finalholidayinabsence -= 0.5 weekdays = [6,7] freedaycounter = 0 for dt in daterange(absence.start, absence.end): if dt.isoweekday() not in weekdays: finalholidayinabsence += 1 for freeday in allfreedays.all(): # FREEDAY FOUND if(dt == freeday.day): freedaycounter += 1 return finalholidayinabsence - freedaycounter # Gibt die Woche als Wochentage zurück def daterange(date1, date2): for n in range(int ((date2 - date1).days)+1): yield date1 + timedelta(n)