Zeiterfassung für QS bereit

This commit is contained in:
Holger Trampe 2020-07-26 12:30:54 +02:00
parent a8ba4a3ad5
commit 1702272929
9 changed files with 514 additions and 134 deletions

View File

@ -22,7 +22,7 @@ def setvar(value):
return ''
@register.simple_tag
def getvar():
def getvar():
global b
return b
@ -30,9 +30,9 @@ def getvar():
def incvar():
global b
b += 1
return ''
return ''
@register.filter(name='has_group')
def has_group(user, group_name):
group = Group.objects.get(name=group_name)
@ -41,7 +41,7 @@ def has_group(user, group_name):
if g.name == group_name:
in_group = True
return in_group
@register.simple_tag
def setbool(value):
global groupbool
@ -49,8 +49,8 @@ def setbool(value):
return ''
@register.simple_tag
def getbool():
global groupbool
def getbool():
global groupbool
return groupbool
@ -72,9 +72,9 @@ def getmesscounter(user):
'''
@register.filter(name="usergperm")
def usergperm(user, perm):
stat = False
stat = False
if user.has_perm('users.'+perm):
stat = True
stat = True
return stat
@register.filter(name="useringroupbyid")
@ -94,7 +94,7 @@ def filename(value):
# Gibt die Summe aller Agenturen eines Agentuverbundes zurück
@register.simple_tag
def getsumofallag(agn_id):
def getsumofallag(agn_id):
return len(AgencyNetwork.objects.get(pk=agn_id).adminagencys.all()) + len(AgencyNetwork.objects.get(pk=agn_id).members.all()) + len(AgencyNetwork.objects.get(pk=agn_id).sharemembers.all())
# Gibt die Summe aller Standards in einem Agenturverband zurück
@ -123,7 +123,7 @@ def ifaginadminagn(agn_id, agencyid):
agency_is_admin = True
return agency_is_admin
@register.simple_tag
def ifmember(agn_id, agencyid):
@ -135,7 +135,7 @@ def ifmember(agn_id, agencyid):
ismember = True
return ismember
@register.simple_tag
def ifsharemember(agn_id, agencyid):
agn = AgencyNetwork.objects.get(pk=agn_id)
@ -167,7 +167,7 @@ def getoutstandinginvites(agnetwork):
@register.simple_tag
def checkifsharedstandardinagency(agency, standard):
checkstandard = Standards.objects.filter(agency=agency, parent_standard=standard)
in_agency = False
@ -185,7 +185,7 @@ def getcommentsdown(comment):
counter_down = len(StandardCommentRate.objects.filter(oncomment=comment, rate_stats=0))
return counter_down
@register.simple_tag
def getcommentsup(comment):
comment_ratings = StandardCommentRate.objects.filter(oncomment_id=comment)
@ -201,10 +201,10 @@ def getcommentstat_user(comment, user):
comment_rating = list(StandardCommentRate.objects.filter(oncomment_id=comment, rated_by=user))
stat = "nostat"
if len(comment_rating) == 1:
stat = comment_rating[0].rate_stats
return stat
@register.simple_tag
@ -230,7 +230,7 @@ def isUserInAuth(task, area, user_id):
if len(st_auth) > 0:
found = True
return found
@register.simple_tag
@ -246,10 +246,10 @@ def isUserInEx(task, area, user_id):
if len(st_auth) > 0:
found = True
return found
@register.simple_tag
def isUserInRep(task, area, user_id):
@ -268,11 +268,11 @@ def isUserInRep(task, area, user_id):
# Check for active WorkDay
@register.simple_tag
def getactualworkingday(user):
wd = Workday.objects.filter(user=user, agency=user.profile.agency, end=None)
wd = Workday.objects.filter(user=user, agency=user.profile.agency, end=None)
returnstat = 0
if(len(wd) > 0):
returnstat = list(wd)[0].start
returnstat = list(wd)[0].start
return returnstat
# Return formatted Time-String
@ -303,7 +303,7 @@ def getformattetstarttime_last_end(user):
@register.simple_tag
def getactualbreak(user):
wd = Workday.objects.filter(user=user, agency=user.profile.agency, end=None)
wd = Workday.objects.filter(user=user, agency=user.profile.agency, end=None)
returnstat = 0
# ACTIVE WORKING DAY
if(len(wd) > 0):
@ -314,26 +314,26 @@ def getactualbreak(user):
# Check if all Breaks ended
wdbreak = wd.breaks.filter(end=None)
if(len(wdbreak) > 0):
returnstat = True
returnstat = True
else:
returnstat = False
return returnstat
@register.simple_tag
def getactualbreakcounter(user):
wd = Workday.objects.filter(user=user, agency=user.profile.agency, end=None)
wd = Workday.objects.filter(user=user, agency=user.profile.agency, end=None)
returnstat = False
# ACTIVE WORKING DAY
if(len(wd) > 0):
wd = list(wd)[0]
if(len(wd.breaks.all()) > 0):
wdbreak = wd.breaks.filter(end=None)
wdbreak = wd.breaks.filter(end=None)
if(len(wdbreak) > 0):
now = timezone.now()
breakstart = list(wdbreak)[0].start
returnstat = (now - breakstart).seconds * 1000
returnstat = (now - breakstart).seconds * 1000
return returnstat
# GET ALL BREAK AS MILLISECOND-RESULT
@ -343,7 +343,7 @@ def getdailybreaktime(user):
breaksum = 0
for b in wd.breaks.all():
if(b.end != None):
breaksum += (b.end - b.start).seconds
breaksum += (b.end - b.start).seconds
return breaksum*1000
@register.simple_tag
@ -353,7 +353,7 @@ def getdailybreaktimetoday(user):
breaksum = 0
for b in wd.breaks.all():
if(b.end != None):
breaksum += (b.end - b.start).seconds
breaksum += (b.end - b.start).seconds
return breaksum*1000
@register.simple_tag
@ -362,10 +362,10 @@ def getsumworkday(workday):
sum_break = 0
if(len(workday.breaks.all()) > 0):
for ele in workday.breaks.all():
sum_break += (ele.end - ele.start).seconds
sum_break += (ele.end - ele.start).seconds
finalsum = ((workday.end - workday.start).seconds - sum_break)
mon, sec = divmod(finalsum, 60)
@ -387,10 +387,10 @@ def getsumbreak(workday):
sum_break = 0
if(len(workday.breaks.all()) > 0):
for ele in workday.breaks.all():
sum_break += (ele.end - ele.start).seconds
sum_break += (ele.end - ele.start).seconds
return int(sum_break/60)
# DATE TIME HELPTER
@ -410,7 +410,7 @@ def getactdateforloopcounter():
@register.simple_tag
def isfreeday(user, daytocheck):
returnstat = False
fd = FreeDays.objects.filter(agency=user.profile.agency, day=daytocheck)
fd = FreeDays.objects.filter(agency=user.profile.agency, day=daytocheck)
if len(fd) > 0:
returnstat = True
return returnstat
@ -418,10 +418,10 @@ def isfreeday(user, daytocheck):
@register.simple_tag
def isfreedayname(user, daytocheck):
returnstat = False
fd = FreeDays.objects.filter(agency=user.profile.agency, day=daytocheck)
fd = FreeDays.objects.filter(agency=user.profile.agency, day=daytocheck)
if len(fd) > 0:
returnstat = True
returnstat = fd[0].name
returnstat = fd[0].name
return returnstat
# RETURN ALL ABSENCE ELEMENTS FOR THAT DAY
@ -430,7 +430,7 @@ def getabscenceday(loggeduser, user, daytocheck):
returnstat = False
if(loggeduser.has_perm("users.absencemanager")):
absencedays = Absence.objects.filter(agency=user.profile.agency, user=user, start=daytocheck) | (Absence.objects.filter(agency=user.profile.agency, user=user, start__lt=daytocheck) & Absence.objects.filter(agency=user.profile.agency, user=user, end__gt=daytocheck)) | Absence.objects.filter(agency=user.profile.agency, user=user, end=daytocheck)
absencedays = Absence.objects.filter(agency=user.profile.agency, user=user, start=daytocheck) | (Absence.objects.filter(agency=user.profile.agency, user=user, start__lt=daytocheck) & Absence.objects.filter(agency=user.profile.agency, user=user, end__gt=daytocheck)) | Absence.objects.filter(agency=user.profile.agency, user=user, end=daytocheck)
else:
absencedays = (Absence.objects.filter(agency=user.profile.agency, user=loggeduser, confirm_status=1) | Absence.objects.filter(agency=user.profile.agency, user=user, confirm_status=0)) & (Absence.objects.filter(agency=user.profile.agency, user=user, start=daytocheck) | (Absence.objects.filter(agency=user.profile.agency, user=user, start__lt=daytocheck) & Absence.objects.filter(agency=user.profile.agency, user=user, end__gt=daytocheck)) | Absence.objects.filter(agency=user.profile.agency, user=user, end=daytocheck) )
if(len(absencedays) > 0):
@ -481,7 +481,7 @@ def getMessageDayInfo(info):
return True
else:
return False
@register.simple_tag
def getUserIsRep(user):
# REPRESENTATOR
@ -502,15 +502,15 @@ def getUserIsRep(user):
absence_holiday = Absence.objects.filter(agency=user.profile.agency, user=user, start__lte=today, end__gte=today, reason__is_holiday=True, confirm_status=0)
if(len(absence_holiday) > 0):
repstring = "Wir wünschen Ihnen noch bis zum " + absence_holiday[0].end.strftime("%d.%m.%Y") + " einen schönen Urlaub!"
repstring = "Wir wünschen Ihnen noch bis zum " + absence_holiday[0].end.strftime("%d.%m.%Y") + " einen schönen Urlaub!"
return repstring
return repstring
# Check, if a user is behind a day in agency (working startdate)
@register.simple_tag
def startdatecheck(usertocheck, day):
uertime = list(UserTime.objects.filter(user=usertocheck))[0]
if uertime.startdate < day:
return True
else:
@ -522,13 +522,13 @@ def gettimeoveralldiff(workday, user):
sum_break = 0
if(len(workday.breaks.all()) > 0):
for ele in workday.breaks.all():
sum_break += (ele.end - ele.start).seconds
sum_break += (ele.end - ele.start).seconds
finalsum = ((workday.end - workday.start).seconds - sum_break)
hastowork = datetime.timedelta(hours=workday.target)
# Finale Summe Arbeitszeit inkl. Pausen und Arbeitszeit an diesem Tag
final_info = (int(finalsum) - int(hastowork.total_seconds()))/60
@ -551,24 +551,30 @@ def gettimeoveralldiff(workday, user):
# Ladet das aktuelle Gleitzeitkonto
'''
Es werden nur Tage berücksichtigt, die in der Vergangenheit liegen!
'''
@register.simple_tag
def loadaccounttime(user):
status = 0
workdays = Workday.objects.filter(user=user).exclude(end=None)
today = date.today()
workdays = Workday.objects.filter(user=user, start__lt=today).exclude(end=None)
finalaccounttimesum = datetime.timedelta(minutes=0)
for workday in workdays:
# Zeit, die der Mitarbeiter gearbeitet haben MUSS
# Zeit, die der Mitarbeiter gearbeitet haben MUSS
sum_break = 0
if(len(workday.breaks.all()) > 0):
for ele in workday.breaks.all():
sum_break += (ele.end - ele.start).seconds
sum_break += (ele.end - ele.start).seconds
finalsum = ((workday.end - workday.start).seconds - sum_break)
hastowork = datetime.timedelta(hours=workday.target)
final_info = (int(finalsum) - int(hastowork.total_seconds()))/60
@ -579,7 +585,7 @@ def loadaccounttime(user):
final_info = final_info * -1
finalaccounttimesum -= datetime.timedelta(minutes=final_info)
# Gesamtgleitzeit einmal schick darstellen mit rot und grün
# Wenn GLeitzeit NEGATIV ist
if(finalaccounttimesum.total_seconds() < 0):
@ -588,7 +594,7 @@ def loadaccounttime(user):
else:
status = 0
final_info_data = str(datetime.timedelta(seconds=finalaccounttimesum.total_seconds())).split(":")
final_info = str(final_info_data[0]) + ":" + str(final_info_data[1])
return [final_info, status]
@ -615,13 +621,13 @@ def getthisdaynotworking(user, day):
elif(day.isoweekday() == 4):
if user.usertime.wd_th == 0.0:
stat = True
elif(day.isoweekday() == 5):
elif(day.isoweekday() == 5):
if user.usertime.wd_fr == 0.0:
stat = True
elif(day.isoweekday() == 6):
elif(day.isoweekday() == 6):
if user.usertime.wd_sa == 0.0:
stat = True
elif(day.isoweekday() == 7):
elif(day.isoweekday() == 7):
if user.usertime.wd_so == 0.0:
stat = True
return stat

View File

@ -9,8 +9,8 @@ class AddAbsence(forms.ModelForm):
class Meta:
model = Absence
labels = {
"start" : "Beginn der Abwesenheit",
"start_ishalf" : "Halber Tag?",
"start" : "Beginn der Abwesenheit",
"start_ishalf" : "Halber Tag?",
"end" : "Ende der Abwesenheit",
"end_ishalf" : "Halber Tag?",
"reason" : "Abwesenheitsgrund",
@ -20,14 +20,14 @@ class AddAbsence(forms.ModelForm):
"endday_info" : ""
}
widgets = {
'start': DatePickerInput(options={"format":'DD.MM.YYYY', "locale":'de'}),
'end': DatePickerInput(options={"format":'DD.MM.YYYY', "locale":'de'}),
'start': DatePickerInput(options={"format":'DD.MM.YYYY', "locale":'de'}),
'end': DatePickerInput(options={"format":'DD.MM.YYYY', "locale":'de'}),
}
#fields = ['start', 'start_ishalf', 'end','end_ishalf', 'reason', "representator", 'info']
fields = ['start', 'startday_info', 'end','endday_info', 'reason', "representator", 'info']
def __init__(self, *arg, **kwargs):
super(AddAbsence, self).__init__(*arg, **kwargs)
self.fields['reason'].queryset = AbsenceReason.objects.filter(agency=kwargs['instance'].profile.agency).order_by('-name')
@ -48,12 +48,12 @@ class AddAbsence(forms.ModelForm):
class UpdateAbsence(forms.ModelForm):
class Meta:
model = Absence
labels = {
"start" : "Beginn der Abwesenheit",
"start_ishalf" : "Halber Tag?",
"start" : "Beginn der Abwesenheit",
"start_ishalf" : "Halber Tag?",
"end" : "Ende der Abwesenheit",
"end_ishalf" : "Halber Tag?",
"reason" : "Abwesenheitsgrund",
@ -63,14 +63,14 @@ class UpdateAbsence(forms.ModelForm):
"endday_info" : ""
}
widgets = {
'start': DatePickerInput(options={"format":'DD.MM.YYYY', "locale":'de'}),
'end': DatePickerInput(options={"format":'DD.MM.YYYY', "locale":'de'}),
'start': DatePickerInput(options={"format":'DD.MM.YYYY', "locale":'de'}),
'end': DatePickerInput(options={"format":'DD.MM.YYYY', "locale":'de'}),
}
#fields = ['start', 'start_ishalf', 'end','end_ishalf', 'reason', "representator", 'info']
fields = ['start', 'startday_info', 'end','endday_info', 'reason', "representator", 'info', 'holidays_normal', 'holidays_rest', 'holidays_normal_next', 'holidays_rest_next' ]
def __init__(self, *arg, **kwargs):
super(UpdateAbsence, self).__init__(*arg, **kwargs)
self.fields['reason'].queryset = AbsenceReason.objects.filter(agency=kwargs['instance'].profile.agency).order_by('-name')
@ -107,7 +107,7 @@ class ConfirmAbsenceForm(forms.ModelForm):
class Meta:
model = Absence
labels = {
labels = {
"confirm_info" : "Begründung zur Annahme/zur Ablehnung"
}
fields = ['confirm_info']
@ -130,7 +130,7 @@ class AddFreeDayForm(forms.ModelForm):
"name", "day"
]
widgets = {
'day': DatePickerInput(options={"format":'DD.MM.YYYY', "locale":'de'}),
'day': DatePickerInput(options={"format":'DD.MM.YYYY', "locale":'de'}),
}
def __init__(self, *arg, **kwargs):
@ -153,15 +153,38 @@ class UpdateWorkdayForm(forms.ModelForm):
"start", "end", "target"
]
widgets = {
'start': DatePickerInput(options={"format":'HH:mm', "locale":'de'}),
'end': DatePickerInput(options={"format":'HH:mm', "locale":'de'}),
'start': DatePickerInput(options={"format":'HH:mm', "locale":'de'}),
'end': DatePickerInput(options={"format":'HH:mm', "locale":'de'}),
}
def __init__(self, *arg, **kwargs):
super(UpdateWorkdayForm, self).__init__(*arg, **kwargs)
self.fields['start'].required = True
self.fields['end'].required = True
# ADD WORKDAY FORM
class AddWorkdayForm(forms.ModelForm):
class Meta:
model = Workday
labels = {
"start" : "Start",
"end" : "Ende",
"target" : "Zielarbeitszeit"
}
fields = [
"start", "end", "target"
]
widgets = {
'start': DatePickerInput(options={"format":'DD.MM.YYYY HH:mm', "locale":'de'}),
'end': DatePickerInput(options={"format":'DD.MM.YYYY HH:mm', "locale":'de'}),
}
def __init__(self, *arg, **kwargs):
super(AddWorkdayForm, self).__init__(*arg, **kwargs)
self.fields['start'].required = True
self.fields['end'].required = True
# ADD BREAK FORM
class AddBreakForm(forms.ModelForm):
class Meta:
@ -175,11 +198,11 @@ class AddBreakForm(forms.ModelForm):
"start", "end"
]
widgets = {
'start': DatePickerInput(options={"format":'HH:mm', "locale":'de'}),
'end': DatePickerInput(options={"format":'HH:mm', "locale":'de'}),
'start': DatePickerInput(options={"format":'HH:mm', "locale":'de'}),
'end': DatePickerInput(options={"format":'HH:mm', "locale":'de'}),
}
def __init__(self, *arg, **kwargs):
super(AddBreakForm, self).__init__(*arg, **kwargs)
self.fields['start'].required = True
self.fields['end'].required = True
self.fields['end'].required = True

View File

@ -0,0 +1,22 @@
{% extends "users/base.html" %}
{% block content %}
{% load crispy_forms_tags %}
{% load counter_tag %}
{% if request.user.profile.agency.module_timemanagement %}
<div class="content-section col-5">
<h3>Arbeitstag hinzufügen</h3>
<hr>
<h5>Start- und Endzeitpunkt</h5>
<div class="col-6" style="margin-left: -10px;">
<form method="POST" class="">
{% csrf_token %}
{{form.media}}
{{form|crispy}}
</div>
<hr>
<a class="btn" href="{% url 'tm-management' %} ">Abbrechen</a>
<button type="submit" class="btn btn-primary" style="float: right" id="addbreakbutton">Arbeitstag hinzufügen</button>
</form>
</div>
{% endif %}
{% endblock content %}

View File

@ -4,7 +4,7 @@
{% if request.user.profile.agency.module_timemanagement %}
<div class="content-section col-12">
<h3>Zeiterfassung&nbsp;<small><i data-toggle="tooltip" data-placement="top" title="Bearbeiten Sie hier Ihre Zeiterfassung." class="far fa-question-circle"></i></small>
<button type="button" class="btn btn-primary btn-sm" style="position: relative; float: right !important;" onclick=""><i class="fas fa-plus"></i>&nbsp;Arbeitstag</button>
<a type="button" class="btn btn-primary btn-sm" style="position: relative; float: right !important;" href="{% url 'tm-add' %}"><i class="fas fa-plus"></i>&nbsp;Arbeitstag</a>
</h3>
<hr>
@ -15,48 +15,130 @@
<button type="button" class="btn btn-primary mr-1" style="min-width: 150px !important;" onclick="">{{active_month}} {{active_year}}</button>
<a type="button" class="btn btn-primary mr-1" href="{% url 'tm-management' next_month next_year %}"><i class="fas fa-arrow-circle-right"></i></a>
</div>
{% for workday in workdays %}
{% if workday.start.weekday == 0 and forloop.counter > 1%}
</div>
<div class="col-12 mb-2" style="float: left;">
<hr>
<div style="float: left;"><h4>{{workday.start|date:"W"}}. Woche</h4></div>
<br /><br />
{% elif forloop.counter == 1 %}
<div class="col-12 mb-2" style="float: left;">
<hr>
<div style="float: left;"><h4>{{workday.start|date:"W"}}. Woche</h4></div>
<br /><br />
{% endif %}
<div class="card col-2 mr-2" style="float: left; margin-top: -12px;">
<div class="card-body">
<h5 class="card-title">{{workday.start|date:"l"}}, {{workday.start|date:"d.m"}}</h5>
Von {{workday.start|date:"H:i"}} bis {{workday.end|date:"H:i"}}<br />
<small>
{% getsumworkdayexcludebreak workday as sumworkday %}
Arbeitszeit: {{ sumworkday }}<br />
{% getsumbreak workday as sumbreakofday %}
Pausen: {{sumbreakofday}} min. ({{workday.breaks.all|length}})
{% getsumworkday workday as sumwd %}<br />
Gesamtzeit: {{sumwd}}<br />
Gleitzeit:
{% gettimeoveralldiff workday user as erg%}
{% if erg.1 == 0 %}
<span style="color: green">+{{erg.0}}</span>
{% elif erg.1 == 1 %}
<span>{{erg.0}}</span>
{% else %}
<span style="color: red">-{{erg.0}}</span>
{% endif %}
</small>
<button style="float: right; margin-right: 10px; margin-bottom: -40px;" class="btn btn-secondary btn-sm " onclick="javascript:$('#confirm-delete_{{workday.pk}}').modal('toggle')"><small><i class="fas fa-trash"></i></small></button>
<button style="float: right; margin-right: -22px; margin-bottom: -40px;" class="btn btn-secondary btn-sm ml-2" onclick="window.location.href='{% url 'tm-update' workday.pk %}'"><small><i class="fas fa-pen"></i></small></button>
<hr>
<div class="table-responsive ">
<table class="table table-hover" id="table_timemanagement" >
<thead>
<tr>
<th scope="col"></th>
<th scope="col"></th>
<th scope="col">Start</th>
<th scope="col">Ende</th>
<th scope="col">Arbeitszeit</th>
<th scope="col">Pausen</th>
<th scope="col">Gesamtzeit</th>
<th scope="col">Gleitzeit</th>
<th scope="col">&nbsp;</th>
</tr>
</thead>
<tbody id="table_contacts" >
{% for da in days_this_month %}
{% getabscenceday request.user request.user da as abday %}
<tr id="da_{{da|date:"d-m-y"}}"
{% if da.weekday == 5 or da.weekday == 6 %}
style="background-color: #d3d3d3;"
{% elif abday != False %}
style="background-color: {{abday.reason.color}}; color: #ffffff"
{% endif %}>
<td>
{{da|date:"l"}}
</td>
<td>
{{da|date:"d.m.y"}}
</td>
<td>
{% if abday != False %}
{{abday.reason}}
{% else %}
{% if abday == False %}
{% for workday in workdays %}
{% if workday.start|date:"d-m-y" == da|date:"d-m-y" %}
{{workday.start|date:"H:i"}}
{% endif %}
{% endfor %}
{% endif %}
{% endif %}
</td>
<td>
{% if abday == False %}
{% for workday in workdays %}
{% if workday.end|date:"d-m-y" == da|date:"d-m-y" %}
{{workday.end|date:"H:i"}}
{% endif %}
{% endfor %}
{% endif %}
</td>
<td>
{% if abday == False %}
{% for workday in workdays %}
{% if workday.start|date:"d-m-y" == da|date:"d-m-y" %}
{% getsumworkdayexcludebreak workday as sumworkday %}
{{ sumworkday }}
{% endif %}
{% endfor %}
{% endif %}
</td>
<td>
{% if abday == False %}
{% for workday in workdays %}
{% if workday.start|date:"d-m-y" == da|date:"d-m-y" %}
{% getsumbreak workday as sumbreakofday %}
{{sumbreakofday}} min. ({{workday.breaks.all|length}})
{% endif %}
{% endfor %}
{% endif %}
</td>
<td>
{% if abday == False %}
{% for workday in workdays %}
{% if workday.start|date:"d-m-y" == da|date:"d-m-y" %}
{% getsumworkday workday as sumwd %}
{{sumwd}}
{% endif %}
{% endfor %}
{% endif %}
</td>
<td>
{% if abday == False %}
{% for workday in workdays %}
{% if workday.start|date:"d-m-y" == da|date:"d-m-y" %}
{% gettimeoveralldiff workday user as erg%}
{% if erg.1 == 0 %}
<span style="color: green">+{{erg.0}}</span>
{% elif erg.1 == 1 %}
<span>{{erg.0}}</span>
{% else %}
<span style="color: red">-{{erg.0}}</span>
{% endif %}
{% endif %}
{% endfor %}
{% endif %}
</td>
<td>
{% if abday == False %}
{% for workday in workdays %}
{% if workday.start|date:"d-m-y" == da|date:"d-m-y" %}
<button class="btn btn-secondary btn-sm ml-2" onclick="window.location.href='{% url 'tm-update' workday.pk %}'"><small><i class="fas fa-pen"></i></small></button>
<button class="btn btn-secondary btn-sm " onclick="javascript:$('#confirm-delete_{{workday.pk}}').modal('toggle')"><small><i class="fas fa-trash"></i></small></button>
{% endif %}
{% endfor %}
{% endif %}
</td>
</tr>
{% endfor %}
</tbody>
</table>
</div>
</div>
{% endfor %}
</div> <!-- CLOSE GRID DAY DIV -->
{% if user.usertime.usetime_start == None %}
<div class="modal fade" tabindex="-1" role="dialog" data-backdrop="static" id="missingdatainfo">
<div class="modal-dialog" role="document">
@ -99,7 +181,7 @@
</button>
</div>
<div class="modal-body">
Es wurden keine Arbeitstage bis zum Beginn der Zeiterfassung am {{user.usertime.usetime_start|date:"d.m.Y"}} gefunden. Sollen diese Tage mit der Regelarbeitszeit aufgefüllt werden, welche bei den Vertragsdaten hinterlegt wurde?
Es wurden keine Arbeitstage bis zum Beginn der Zeiterfassung am {{user.usertime.usetime_start|date:"d.m.Y"}} gefunden. Sollen diese Tage mit der Regelarbeitszeit aufgefüllt werden, welche bei den Vertragsdaten hinterlegt wurde? Abwesenheiten werden nicht berücksichtigt!
</div>
<div class="modal-footer">
<button type="button" class="btn btn-primary" onclick="javascript:loadInitiDays()">Ja</button>
@ -152,7 +234,6 @@
</div>
</div>
<script type="text/javascript">
$("#dodel_{{workday.pk}}").click(function(){
$.ajax(
{
@ -164,8 +245,7 @@
},
success: function( data )
{
$("#wd_{{workday.pk}}").remove();
$("#confirm-delete_{{workday.pk}}").modal("toggle");
location.href = location.href;
}
});
});
@ -197,7 +277,9 @@ $(document).ready(function(){
},
"buttons" : {
"className" : "btn-danger"
}
},
"pageLength": 50,
"order": [[ 1, "asc" ]]
});
});

View File

@ -0,0 +1,208 @@
{% extends "users/base.html" %}
{% block content %}
{% load counter_tag %}
{% if request.user.profile.agency.module_timemanagement %}
<div class="content-section col-12">
<h3>Zeiterfassung&nbsp;<small><i data-toggle="tooltip" data-placement="top" title="Bearbeiten Sie hier Ihre Zeiterfassung." class="far fa-question-circle"></i></small>
<button type="button" class="btn btn-primary btn-sm" style="position: relative; float: right !important;" onclick=""><i class="fas fa-plus"></i>&nbsp;Arbeitstag</button>
</h3>
<hr>
<!-- TODO: Hier noch Jahr speichern und Monat usw. -->
<div class="btn-group" role="group" aria-label="" style="min-width: 100% !important">
<a type="button" class="btn btn-primary mr-1" href="{% url 'tm-management' prev_month prev_year %}" ><i class="fas fa-arrow-circle-left"></i></a>
<button type="button" class="btn btn-primary mr-1" style="min-width: 150px !important;" onclick="">{{active_month}} {{active_year}}</button>
<a type="button" class="btn btn-primary mr-1" href="{% url 'tm-management' next_month next_year %}"><i class="fas fa-arrow-circle-right"></i></a>
</div>
{% for workday in workdays %}
{% if workday.start.weekday == 0 and forloop.counter > 1%}
</div>
<div class="col-12 mb-2" style="float: left;">
<hr>
<div style="float: left;"><h4>{{workday.start|date:"W"}}. Woche</h4></div>
<br /><br />
{% elif forloop.counter == 1 %}
<div class="col-12 mb-2" style="float: left;">
<hr>
<div style="float: left;"><h4>{{workday.start|date:"W"}}. Woche</h4></div>
<br /><br />
{% endif %}
<div class="card col-2 mr-2" style="float: left; margin-top: -12px;">
<div class="card-body">
<h5 class="card-title">{{workday.start|date:"l"}}, {{workday.start|date:"d.m"}}</h5>
Von {{workday.start|date:"H:i"}} bis {{workday.end|date:"H:i"}}<br />
<small>
{% getsumworkdayexcludebreak workday as sumworkday %}
Arbeitszeit: {{ sumworkday }}<br />
{% getsumbreak workday as sumbreakofday %}
Pausen: {{sumbreakofday}} min. ({{workday.breaks.all|length}})
{% getsumworkday workday as sumwd %}<br />
Gesamtzeit: {{sumwd}}<br />
Gleitzeit:
{% gettimeoveralldiff workday user as erg%}
{% if erg.1 == 0 %}
<span style="color: green">+{{erg.0}}</span>
{% elif erg.1 == 1 %}
<span>{{erg.0}}</span>
{% else %}
<span style="color: red">-{{erg.0}}</span>
{% endif %}
</small>
<button style="float: right; margin-right: 10px; margin-bottom: -40px;" class="btn btn-secondary btn-sm " onclick="javascript:$('#confirm-delete_{{workday.pk}}').modal('toggle')"><small><i class="fas fa-trash"></i></small></button>
<button style="float: right; margin-right: -22px; margin-bottom: -40px;" class="btn btn-secondary btn-sm ml-2" onclick="window.location.href='{% url 'tm-update' workday.pk %}'"><small><i class="fas fa-pen"></i></small></button>
</div>
</div>
{% endfor %}
</div> <!-- CLOSE GRID DAY DIV -->
{% if user.usertime.usetime_start == None %}
<div class="modal fade" tabindex="-1" role="dialog" data-backdrop="static" id="missingdatainfo">
<div class="modal-dialog" role="document">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title">Fehlende Informationen</h5>
<button type="button" class="close" data-dismiss="modal" aria-label="Close">
<span aria-hidden="true">&times;</span>
</button>
</div>
<div class="modal-body">
Achtung! Es wurde kein Datum gefunden, ab wann die Zeiterfassung beginnen soll. Bitte tragen Sie dies in Ihrem Mitarbeiterkonto unter Einstellungen, Mitarbeiter, Ihre Vertragsdaten nach.
<br />
<small>Dies können nur Mitarbeiter eintragen, die das Recht haben, Mitarbeiter zu verwalten.</small>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-primary" data-dismiss="modal">Schließen</button>
</div>
</div>
</div>
</div>
<script type="text/javascript">
$(document).ready(function(){
$("#missingdatainfo").modal("toggle");
})
$('#missingdatainfo').on('hidden.bs.modal', function (e) {
location.href = "{% url 'dasettings' %}";
})
</script>
{% elif userhasworkdays == False %}
<div class="modal fade" tabindex="-1" role="dialog" data-backdrop="static" id="initialload">
<div class="modal-dialog" role="document">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title">Arbeitstage auffüllen</h5>
<button type="button" class="close" data-dismiss="modal" aria-label="Close">
<span aria-hidden="true">&times;</span>
</button>
</div>
<div class="modal-body">
Es wurden keine Arbeitstage bis zum Beginn der Zeiterfassung am {{user.usertime.usetime_start|date:"d.m.Y"}} gefunden. Sollen diese Tage mit der Regelarbeitszeit aufgefüllt werden, welche bei den Vertragsdaten hinterlegt wurde? Abwesenheiten werden nicht berücksichtigt!
</div>
<div class="modal-footer">
<button type="button" class="btn btn-primary" onclick="javascript:loadInitiDays()">Ja</button>
<button type="button" class="btn btn" data-dismiss="modal">Nein</button>
</div>
</div>
</div>
</div>
<script type="text/javascript">
$(document).ready(function(){
$("#initialload").modal("toggle");
});
function loadInitiDays(){
$.ajax(
{
type: "GET",
url: "{% url 'tm-ajax' %}",
data:{
action : "initial_load",
},
success: function( data )
{
location.href = location.href;
}
});
}
</script>
{% endif %}
{% for workday in workdays %}
<div class="modal fade" id="confirm-delete_{{workday.pk}}" tabindex="-1" role="dialog" aria-labelledby="" aria-hidden="true">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title">Arbeitstag löschen</h5>
</div>
<div class="modal-body">
Möchten Sie wirklich den Arbeitstag am {{workday.start|date:"d.m"}} löschen?
</div>
<div class="modal-footer">
<button class="btn btn-primary" id="dodel_{{workday.pk}}" >Löschen</button>
<button type="button" class="btn" data-dismiss="modal">Abbrechen</button>
</div>
</div>
</div>
</div>
<script type="text/javascript">
$("#dodel_{{workday.pk}}").click(function(){
$.ajax(
{
type: "GET",
url: "{% url 'tm-ajax' %}",
data:{
action : "remove_workday",
workday: {{workday.pk}},
},
success: function( data )
{
$("#wd_{{workday.pk}}").remove();
$("#confirm-delete_{{workday.pk}}").modal("toggle");
}
});
});
</script>
{% endfor %}
<style>
/* DATATABLES */
.paginate_button {
padding: 0px !important;
border: 0px !important;
}
</style>
<script>
$(document).ready(function(){
$('#table_timemanagement').DataTable({
"language": {
"search" : "Suche",
"info": "Zeige _START_ bis _END_ von _TOTAL_ Einträgen",
"lengthMenu": "Zeige _MENU_ Einträge",
"zeroRecords": "Nichts gefunden",
"infoEmpty": "Keine Einträge",
"paginate": {
"first": "Erste",
"last": "Letzte",
"next": "Nächste",
"previous": "Zurück"
},
},
"buttons" : {
"className" : "btn-danger"
}
});
});
</script>
{% else %}
<h3>Das Modul Abwesenheits- und Zeiterfassung wurde in ihrer Agentur deaktiviert oder die Zeiterfassung wurde im Modul deaktiviert.</h3>
{% endif %}
{% endblock content %}

View File

@ -4,7 +4,7 @@
{% load counter_tag %}
{% if request.user.profile.agency.module_timemanagement %}
<div class="content-section col-5">
<h3>Arbeitstag am {{workday.start|date:"d.m.Y"}} bearbeiten</h3>
<hr>
<h5>Start- und Endzeitpunkt</h5>
@ -12,11 +12,11 @@
<form method="POST" class="">
{% csrf_token %}
{{form.media}}
{{form|crispy}}
{{form|crispy}}
</div>
<hr>
<h5>Pausen
<button class="btn btn-primary btn-sm" style="float: right" onclick="window.location.href='{% url 'add-break' workday.pk %}'"><i class="fas fa-plus"></i></button>
<a class="btn btn-primary btn-sm" style="float: right" href="{% url 'add-break' workday.pk %}"><i class="fas fa-plus"></i></a>
</h5>
<div col="col-10">
<table class="table table-hover" >
@ -24,8 +24,8 @@
<tr>
<th scope="col">#</th>
<th scope="col">Start</th>
<th scope="col">Ende</th>
<th scope="col">&nbsp;</th>
<th scope="col">Ende</th>
<th scope="col">&nbsp;</th>
</tr>
</thead>
<tbody>
@ -59,7 +59,7 @@
</div>
<div class="modal-footer">
<button class="btn btn-primary" id="dodel_{{break.pk}}" >Löschen</button>
<button type="button" class="btn" data-dismiss="modal">Abbrechen</button>
<button type="button" class="btn" data-dismiss="modal">Abbrechen</button>
</div>
</div>
</div>
@ -75,12 +75,12 @@
action : "remove_break",
break: {{break.pk}},
},
success: function( data )
{
success: function( data )
{
$("#wd_break_{{break.pk}}").remove();
$("#confirm-delete_{{break.pk}}").modal("toggle");
}
});
});
});
</script>
{% endfor %}
@ -95,7 +95,7 @@ $("#id_start").blur(function(){
checkBreaks();
})
function checkBreaks(){
function checkBreaks(){
$('.ui-datepicker-calendar').hide();
$('.ui-datepicker-header').hide();
@ -111,4 +111,4 @@ function checkBreaks(){
}
</script>
{% endif %}
{% endblock content %}
{% endblock content %}

View File

@ -1,6 +1,6 @@
from django.urls import path
from django.contrib.auth.decorators import login_required, permission_required
from .views import TimeManagement, TimeAjax, AbsenceManagmenet, AbsenceUpdate, TimeUpdate, AddBreak
from .views import TimeManagement, TimeAjax, AbsenceManagmenet, AbsenceUpdate, TimeUpdate, AddBreak, TimeAdd
'''
Permissions definiert in models.py bei USERS und dann hier vor die View geschrieben!
'''
@ -9,6 +9,7 @@ urlpatterns = [
path('', TimeManagement, name='tm-management'),
path('<int:activemonth>/<int:activeyear>', TimeManagement, name='tm-management'),
path('update/<int:pk>', TimeUpdate, name='tm-update'),
path('add/', TimeAdd, name='tm-add'),
path('update/<int:pk>/addbreak/', AddBreak, name='add-break'),
path('abs/', AbsenceManagmenet, name='tma-management'),
path('abs/<int:activemonth>/<int:activeyear>', AbsenceManagmenet, name='tma-management'),

View File

@ -11,7 +11,7 @@ from django.contrib.auth.models import User
from calendar import monthrange
import datetime
import calendar
from .forms import AddAbsence, ConfirmAbsenceForm, UpdateAbsence, UpdateWorkdayForm, AddBreakForm
from .forms import AddAbsence, ConfirmAbsenceForm, UpdateAbsence, UpdateWorkdayForm, AddBreakForm, AddWorkdayForm
from django.contrib import messages
from users.models import UserFullName, UserYearAbsenceInfo
from users.models import UserTime
@ -328,9 +328,11 @@ def TimeManagement(request, activemonth=False, activeyear=False):
"active_year" : active_year,
"active_month" : active_month,
"active_link" : "timemanagement",
"days_this_month" : get_datetime_range(int(active_year), int(activemonth)),
"workdays" : Workday.objects.filter(agency=request.user.profile.agency, user=request.user, start__month=activemonth, start__year=active_year).order_by("start").exclude(end=None),
"userhasworkdays" : user_has_workdays
}
return render(request, 'timemanagement/timemanagement_management.html', context)
@login_required
@ -358,6 +360,42 @@ def TimeUpdate(request, pk):
}
return render(request, 'timemanagement/timemanagement_update.html', context)
@login_required
def TimeAdd(request):
if(request.method == "POST"):
form = AddWorkdayForm(request.POST, instance=request.user)
if form.is_valid():
#start = datetime.datetime(int(workday.start.year), int(workday.start.month), int(workday.start.day), int(((str(form["start"].value()).split(":"))[0])), int(((str(form["start"].value()).split(":"))[1])))
#end = datetime.datetime(int(workday.end.year), int(workday.end.month), int(workday.end.day), int(((str(form["end"].value()).split(":"))[0])), int(((str(form["end"].value()).split(":"))[1])))
workday = Workday(start=form.cleaned_data["start"], end=form.cleaned_data["end"], target=form.cleaned_data["target"], user=request.user, agency=request.user.profile.agency)
if workday.start.day != workday.end.day or workday.start.month != workday.end.month or workday.start.year != workday.end.year or workday.start > workday.end:
messages.success(request, f'Der Arbeitstag darf nur an einem Tag stattfinden und das Ende muss nach dem Anfang liegen.')
context = {
"active_link" : "timemanagement",
"form" : AddWorkdayForm()
}
return render(request, 'timemanagement/timemanagement_add.html', context)
else:
workday.save()
messages.success(request, f'Arbeitstag hinzugefügt')
return redirect('tm-management')
else:
messages.success(request, f'Bitte valide Daten eingeben!')
context = {
"active_link" : "timemanagement",
"form" : AddWorkdayForm()
}
return render(request, 'timemanagement/timemanagement_add.html', context)
else:
context = {
"active_link" : "timemanagement",
"form" : AddWorkdayForm()
}
return render(request, 'timemanagement/timemanagement_add.html', context)
@login_required
def AddBreak(request, pk):
if(request.method == "POST"):