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, UpdateAbsence 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 AbsenceUpdate(request, pk): if request.method == "GET": absence = Absence.objects.get(pk=pk) timeinfo_thisyear = list(UserYearAbsenceInfo.objects.filter(year=absence.start.year, user=absence.user))[0] try: timeinfo_nextyear = list(UserYearAbsenceInfo.objects.filter(year=absence.start.year+1, user=absence.user))[0] except: timeinfo_nextyear = False context = { "active_link" : "abscence", "form" : UpdateAbsence(instance=request.user), "absence" : absence, "timeinfo_thisyear" : timeinfo_thisyear, "timeinfo_nextyear" : timeinfo_nextyear, "start" : absence.start.strftime("%d.%m.%Y"), "end" : absence.end.strftime("%d.%m.%Y"), } return render(request, 'timemanagement/tm_ab_update.html', context) elif request.method == "POST": absence = Absence.objects.get(pk=pk) formtocheck = UpdateAbsence(request.POST, instance=request.user) if(formtocheck.is_valid()): abinfo = list(UserYearAbsenceInfo.objects.filter(user=absence.user, year=absence.start.year))[0] abinfo_lastyear = "" abinfo_nextyear = "" is_lastyear = False abinfo_lastyear = list(UserYearAbsenceInfo.objects.filter(user=absence.user, year=absence.start.year-1)) if(len(abinfo_lastyear) > 0): is_lastyear = True abinfo_lastyear = abinfo_lastyear[0] is_nextyear = False abinfo_nextyear = list(UserYearAbsenceInfo.objects.filter(user=absence.user, year=absence.start.year+1)) if(len(abinfo_nextyear) > 0): is_nextyear = True abinfo_nextyear = abinfo_nextyear[0] print(formtocheck.cleaned_data["holidays_normal"]) print(formtocheck.cleaned_data["holidays_rest"]) print(formtocheck.cleaned_data["startday_info"]) print(formtocheck.cleaned_data["endday_info"]) abinfo.days_inuse -= formtocheck.cleaned_data["holidays_normal"] abinfo.restdays -= formtocheck.cleaned_data["holidays_rest"] abinfo.save() abinfo_nextyear.days_inuse -= formtocheck.cleaned_data["holidays_normal_next"] abinfo_nextyear.restdays -= formtocheck.cleaned_data["holidays_rest_next"] abinfo_nextyear.save() absence.start = formtocheck.cleaned_data["start"] absence.end = formtocheck.cleaned_data["end"] absence.startday_info = str(formtocheck.cleaned_data["startday_info"]) absence.endday_info = str(formtocheck.cleaned_data["endday_info"]) absence.reason = formtocheck.cleaned_data["reason"] rep = None if(formtocheck.cleaned_data["representator"] != None): rep = User.objects.get(pk=formtocheck.cleaned_data["representator"].pk) absence.representator = rep absence.info = formtocheck.cleaned_data["info"] absence.holidays_normal = 0.0 absence.holidays_rest = 0.0 absence.holidays_normal_next = 0.0 absence.holidays_rest_next = 0.0 absence.save() messages.success(request, f'Abwesenheit aktualisiert!') else: messages.success(request, f'Fehler bei Abwesenheitsaktualisierung!') context = { "active_link" : "abscence", } return redirect("tma-management") @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() 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"], startday_info=formtocheck.cleaned_data["startday_info"], endday_info=formtocheck.cleaned_data["endday_info"]).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 # ABSENCE AUFLISTUNG NACH GRUND allreasons = AbsenceReason.objects.filter(agency=request.user.profile.agency).order_by("name") final_reasons = [] for ar in allreasons: tempabsece = Absence.objects.filter(reason=ar, user=request.user, start__year=activeyear) temp_sum = 0.0 for t in tempabsece: temp_sum += calculatingHolidaysByAbsence(request, t) final_reasons.append([ar, temp_sum]) 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, "final_reasons" : final_reasons, "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": absence = Absence.objects.get(pk=request.GET["abscenceid"]) timeinfo_thisyear = list(UserYearAbsenceInfo.objects.filter(year=absence.start.year, user=absence.user))[0] try: timeinfo_nextyear = list(UserYearAbsenceInfo.objects.filter(year=absence.start.year+1, user=absence.user))[0] except: timeinfo_nextyear = False # POrüfen, ob es in diesem Zeitraum noch andere Abwesenheiten gibt other_absences = Absence.objects.filter(start__lte=absence.start, end__gte=absence.end, agency=request.user.profile.agency).exclude(user=absence.user) other_absences_string = False if (len(other_absences) > 0): other_absences_string = [] for a in other_absences: other_absences_string.append(a.user.first_name + " " + a.user.last_name + " - Vom " + a.start.strftime("%d.%m.%Y") + " bis " + a.end.strftime("%d.%m.%Y")) context = { "confirmform" : ConfirmAbsenceForm(instance=request.user), "absence" : absence, "other_absences_string" : other_absences_string, "timeinfo_thisyear" : timeinfo_thisyear, "timeinfo_nextyear" : timeinfo_nextyear } 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])) # GET INFO IF DAY IS HALF OR NOT, EQUAL PRE-POST-DAY start_half = False if request.GET["startday_info"] == "1" or request.GET["startday_info"] == "2": start_half = True end_half = False if request.GET["endday_info"] == "1" or request.GET["endday_info"] == "2": end_half = True 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 holiday_nextyear_rest = 0 two_years = False need_days_next = 0 need_days_this = 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 holiday_nextyear_rest = list(UserYearAbsenceInfo.objects.filter(user=user, agency=user.profile.agency, year=choosenyear+1))[0].restdays 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: two_years = True holiday_lastyear = yeardata.restdays date_splitter = datetime.date(end_day_obj.year, 1, 1) need_days_this = (calculateHolidays(request, start_day_obj, date_splitter, start_half, False))*(-1) need_days_next = (calculateHolidays(request, date_splitter, end_day_obj, False, end_half))*(-1) 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 - need_days_this days_nextyear_normal = 0 days_nextyear_rest = 0 # Urlaub nächstes Jahr MIT und OHNE Rest if(holiday_nextyear_rest == 0.0): holiday_nextyear = holiday_nextyear - (calculateHolidays(request, date_splitter, end_day_obj, False, end_half))*(-1) else: temprest = holiday_nextyear_rest - need_days_next # Rest reicht! if(temprest >= 0): holiday_nextyear_rest = temprest days_nextyear_normal = 0 days_nextyear_rest = need_days_next # Rest reicht nicht else: holiday_nextyear_rest = 0 holiday_nextyear += temprest days_nextyear_rest = need_days_next + temprest days_nextyear_normal = temprest * -1 # POrüfen, ob es in diesem Zeitraum noch andere Abwesenheiten gibt other_absences = Absence.objects.filter(start__lte=start_day_obj, end__gte=end_day_obj, agency=request.user.profile.agency).exclude(user=user) other_absences_string = False if (len(other_absences) > 0): other_absences_string = "" for a in other_absences: other_absences_string += a.user.first_name + " " + a.user.last_name + " - Vom " + a.start.strftime("%d.%m.%Y") + " bis " + a.end.strftime("%d.%m.%Y") + "
" data = { "restholiday_thisyear" : holiday_thisyear, "restholiday_lastyear" : holiday_lastyear, "restholiday_nextyear" : holiday_nextyear, "restholiday_nextyear_rest" : holiday_nextyear_rest, "two_years" : two_years, "need_days" : need_days, "need_days_next" : need_days_next, "need_days_this" : need_days_this, "other_absences" : other_absences_string } # 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.startday_info == "1" or absence.startday_info == "2": finalholidayinabsence = 0.5 else: finalholidayinabsence = 1 return finalholidayinabsence else: if absence.startday_info == "1" or absence.startday_info == "2": finalholidayinabsence -= 0.5 if absence.endday_info == "1" or absence.endday_info == "2": 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)