digitaleagenturnc/timemanagement/views.py

522 lines
16 KiB
Python

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
from users.models import UserTime
from datetime import timedelta
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)
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,
"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
absence.save()
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 and request.user.has_perm("users.absencemanager")):
# Alle Abwesenheiten laden, die bestätigt oder angefragt sind UND Urlaub sind
absences = Absence.objects.filter(user=user, confirm_status=0, reason__is_holiday=True) | Absence.objects.filter(user=user, confirm_status=1, reason__is_holiday=True)
start_day = request.GET["startdate"].split("__")
start_day_ob = 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]))
start_half = True
if request.GET["start_half"] == "false":
start_half = False
end_half = True
if request.GET["end_half"] == "false":
end_half = False
# USER HAS NO ABSENCE
if(len(absences) == 0):
# Hier Urlaubstage bei Einstellung mit berücksichtigen
if(start_day_ob.year == usertimedata.startdate.year):
data = {
"restholiday" : calculateHolidays(request, usertimedata.holiday_start + usertimedata.holiday, start_day_ob, end_day_obj, start_half, end_half)
}
# Hier Einstellungstage irrelevant und da noch keine Abwesenheiten eingetragen wurden, einfach aus Profil laden
else:
data = {
"restholiday" : calculateHolidays(request, usertimedata.holiday, start_day_ob, end_day_obj, start_half, end_half)
}
# ABSENCE-Data found, calculating rest-Days
else:
finalholidays = 0
# Besteht noch Anspruch aus Einstellungsjahr?
if(start_day_ob.year == usertimedata.startdate.year):
finalholidays += usertimedata.holiday_start + usertimedata.holiday
# Hier Einstellungstage irrelevant und da noch keine Abwesenheiten eingetragen wurden, einfach normal
else:
finalholidays += usertimedata.holiday
# Berechne pro Abwesenheits die verbrauchen Urlaubstage
for absence in absences:
finalholidays -= calculatingHolidaysByAbsence(request, absence)
data = {
"restholiday" : calculateHolidays(request, finalholidays, start_day_ob, end_day_obj, start_half, end_half)
}
# 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, restdays, start, end, start_half, end_half):
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)