Zwischencommit Absence

This commit is contained in:
holger.trampe 2020-05-03 21:54:11 +02:00
parent db58c37c82
commit 37070e045d
20 changed files with 1053 additions and 189 deletions

View File

@ -66,15 +66,18 @@ class UserTimeForm(forms.ModelForm):
labels = {
"holiday" : "Urlaubstage",
"loose_holidedate" : "Urlaubstage aus Vorjahr verfallen am",
"startdate" : "Einstellungsdatum",
"holiday_start" : "Urlaubstage bei Einstellung",
"wd_mo" : "Montag",
"wd_tu" : "Dienstag",
"wd_we" : "Mittwoch",
"wd_th" : "Donnerstag",
"wd_fr" : "Freitag",
}
fields = ["holiday", "loose_holidedate", "wd_mo", "wd_tu", "wd_we", "wd_th", "wd_fr"]
fields = ["holiday", "loose_holidedate", "startdate", "holiday_start", "wd_mo", "wd_tu", "wd_we", "wd_th", "wd_fr"]
widgets = {
'loose_holidedate': DatePickerInput(options={"format":'DD.MM.YYYY', "locale":'de'})
'loose_holidedate': DatePickerInput(options={"format":'DD.MM.YYYY', "locale":'de'}),
"startdate" : DatePickerInput(options={"format":'DD.MM.YYYY', "locale":'de'})
}
@ -130,14 +133,14 @@ class UserProfileForm(forms.ModelForm):
class Meta:
model = Profile
labels = {
"persnumber" : "Personalnummer",
"visible" : "Im Organigramm sichtbar",
"phonemobile" : "Mobilnummer",
"phone_public" : "Nur Interne Verwendung der Mobilnummer",
"phoneland" : "Festnetznummer",
"image": "Profilbild",
"func" : "Agenturfunktion",
"compfunc" : "Tätigkeit"
"persnumber" : "Personalnummer",
"visible" : "Im Organigramm sichtbar",
"phonemobile" : "Mobilnummer",
"phone_public" : "Nur Interne Verwendung der Mobilnummer",
"phoneland" : "Festnetznummer",
"image": "Profilbild",
"func" : "Agenturfunktion",
"compfunc" : "Tätigkeit"
}
widgets = {"parent" : forms.HiddenInput()}
fields = ["parent", "func", "compfunc", "visible", "phoneland", "phonemobile", "phone_public", "persnumber", "image" ]

View File

@ -99,7 +99,7 @@
<h5 class="mt-3">Agenturinformationen{% if request.user.profile.showtooltips %}&nbsp;<small><i data-toggle="tooltip" data-placement="top" title="Verwalten Sie hier die Informationen Ihrer Agentur, z.B. Adresse, E-Mailadresse und Telefon." class="far fa-question-circle"></i></small>{% endif %}
</h5>
<hr>
{% block agency_content %}
{% block agency_content %}
{% include "dasettings/agency_content.html" %}
{% endblock %}
</div>

View File

@ -176,7 +176,9 @@
<p>Urlaub&nbsp;<small><i data-toggle="tooltip" data-placement="top" title="Legen Sie fest, wie viel Urlaub dieser Mitarbeiter im Jahr hat." class="far fa-question-circle"></i></small></p>
{{usertime_form.media}}
{{usertime_form.holiday|as_crispy_field}}
{{usertime_form.loose_holidedate|as_crispy_field}}
{{usertime_form.holiday_start|as_crispy_field}}
{{usertime_form.loose_holidedate|as_crispy_field}}
{{usertime_form.startdate|as_crispy_field}}
</div>
<div class="col-12">
<hr>

View File

@ -544,7 +544,6 @@ def UserProfileUpdate(request, pk, newuser=0):
elif(request.POST["form_type"] == "contract"):
formtosave = UserTimeForm(request.POST, instance=UserTime.objects.get(user=usertochange))
print(formtosave)
if(formtosave.is_valid()):
messages.success(request, f'Vertragsdaten gespeichert!')
formtosave.save()
@ -792,8 +791,7 @@ def ManageAgInAgn(request, pk):
for a in network.adminagencys.all():
allagofagn.append(a)
print(allagofagn)
context = {
'active_link' : 'dasettings',
'agn' : list(agn)[0],

View File

@ -29,7 +29,7 @@
{% if perms.users.standardmanager %}
<li class="nav-item" style="float: right !important;">
<a class="nav-link" id="agencys" data-toggle="tab" href="#t_agencys" role="tab" aria-controls="t_agencys" aria-selected="false">
{% if unpubstandards_of_user|length > 0 %}
{% if unpubstandards_of_user|length > 0 %}
<span class="badge badge-primary badge-counter" style="float: right; margin-left: 5px; margin-top: 0px">{{unpubstandards_of_user|length}} </span>&nbsp;
{%endif%}
Unveröffentlichte Standards

View File

@ -2,7 +2,7 @@ from django import template
from django.contrib.auth.models import Group, User
from users.models import AgencyGroup, Agency, AgencyNetwork, AgencyNetworkPreperation
from standards.models import Standards, StandardCommentRate, StandardComments
from timemanagement.models import Workday, FreeDays
from timemanagement.models import Workday, FreeDays, Absence
from message.models import Message
import os
from django.conf import settings
@ -414,4 +414,29 @@ def isfreedayname(user, daytocheck):
if len(fd) > 0:
returnstat = True
returnstat = fd[0].name
return returnstat
return returnstat
# RETURN ALL ABSENCE ELEMENTS FOR THAT DAY
@register.simple_tag
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)
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):
returnstat = list(absencedays)[0]
return returnstat
@register.simple_tag
def getsomeyears(start):
years = []
start_int = int(start)
years = [start_int-4, start_int-3,start_int-2,start_int-1,start_int, start_int+1, start_int+2, start_int+3, start_int+4]
return years
@register.simple_tag
def getsomemonths():
return ["Januar", "Februar", "März", "April", "Mai", "Juni", "Juli", "August", "September", "Oktober", "November", "Dezember"]

View File

@ -1,19 +1,65 @@
from bootstrap_datepicker_plus import DatePickerInput
from django import forms
from django.forms import ModelForm
from .models import Absence
from .models import Absence, AbsenceReason
from users.models import UserFullName
class AddAbsence(forms.ModelForm):
class Meta:
model = Absence
labels = {
"start" : "Beginn der Abwesenheit",
"end" : "Ende der Abwesenheit",
}
fields = ['start', 'end']
"start" : "Beginn der Abwesenheit",
"start_ishalf" : "Halber Tag?",
"end" : "Ende der Abwesenheit",
"end_ishalf" : "Halber Tag?",
"reason" : "Abwesenheitsgrund",
"representator" : "Vertreter",
"info" : "Begründung"
}
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']
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')
self.fields['representator'].queryset = UserFullName.objects.filter(profile__agency=kwargs['instance'].profile.agency)
self.fields['info'].widget.attrs['rows'] = 3
self.fields['start'].required = True
self.fields['end'].required = True
self.fields['reason'].required = True
self.fields['nextmonth'] = forms.CharField(initial="", required=False, widget=forms.HiddenInput())
self.fields['prevmonth'] = forms.CharField(initial="", required=False, widget=forms.HiddenInput())
self.fields['nextyear'] = forms.CharField(initial="", required=False, widget=forms.HiddenInput())
self.fields['prevyear'] = forms.CharField(initial="", required=False, widget=forms.HiddenInput())
self.fields['activemonth'] = forms.CharField(initial="", required=False, widget=forms.HiddenInput())
self.fields['activeyear'] = forms.CharField(initial="", required=False, widget=forms.HiddenInput())
self.fields['userid'] = forms.CharField(initial="", required=False, widget=forms.HiddenInput())
'''
def clean(self):
start_date = self.cleaned_data['start']
end_date = self.cleaned_data['end']
if end_date <= start_date:
raise forms.ValidationError("Das Ende der Abwesenheit muss am oder nach dem Start der Abwesenheit liegen.")
return super(AddAbsence, self).clean()
'''
class ConfirmAbsenceForm(forms.ModelForm):
class Meta:
model = Absence
labels = {
"confirm_info" : "Begründung zur Annahme/zur Ablehnung"
}
fields = ['confirm_info']
def __init__(self, *arg, **kwargs):
super(ConfirmAbsenceForm, self).__init__(*arg, **kwargs)
self.fields['confirm_info'].widget.attrs['rows'] = 3

View File

@ -1,6 +1,7 @@
from django.db import models
from django.contrib.auth.models import User
from users.models import Agency
from django.core.exceptions import ValidationError
# Create your models here.
class Workday(models.Model):
@ -24,17 +25,31 @@ class AbsenceReason(models.Model):
need_rep = models.BooleanField(default=True)
is_holiday = models.BooleanField(default=True)
def __str__(self):
return f'{self.name}'
class Absence(models.Model):
user = models.ForeignKey(User, on_delete=models.CASCADE)
agency = models.ForeignKey(Agency, on_delete=models.CASCADE)
start = models.DateTimeField(default=None, null=True, blank=True)
end = models.DateTimeField(default=None, null=True, blank=True)
start_ishalf = models.BooleanField(default=False)
end_ishalf = models.BooleanField(default=False)
start_ishalf = models.BooleanField(default=False, blank=True)
end_ishalf = models.BooleanField(default=False, blank=True)
reason = models.ForeignKey("AbsenceReason", on_delete=models.SET_NULL, null=True, blank=True)
info = models.TextField(blank=True, verbose_name='Abwesenheitsbegründung', default="")
'''
CONFIRM_STATUS INFOS
0 = NO NEED TO CONFIRM AND CONFORM OK
1 = IS CONFIRMED, AWAITING OK
2 = NOT CONFIRMED
'''
confirm_status = models.IntegerField(default=0)
confirm_info = models.TextField(blank=True, verbose_name='Begründung', default="")
representator = models.ForeignKey(User, blank=True, default=None, null=True, on_delete=models.CASCADE, related_name="Vertreter")
class FreeDays(models.Model):
agency = models.ForeignKey(Agency, on_delete=models.CASCADE)

View File

@ -0,0 +1,23 @@
{% load crispy_forms_tags %}
<h5>Abwesenheit für {{absence.user.first_name}} {{absence.user.last_name}} annehmen oder ablehnen</h5>
<hr>
<h6>Informationen der Abwesenheit</h6>
Von: {{absence.start|date:"d.m Y"}}<br />
Bis: {{absence.end|date:"d.m Y"}}<br />
Grund: {{absence.reason.name}}<br />
Informationen: {{absence.info}}<br />
<hr>
<form method="POST">
<input type="hidden" name="form_type" value="confirmform">
{% csrf_token %}
{{confirmform|crispy}}
</div>
<div class="modal-footer">
<button type="button" class="btn btn-success" onclick="javascript:noconfirmAbsence({{absence.pk}})">Ablehnen</button>
<button type="button" class="btn btn-danger" onclick="javascript:confirmAbsence({{absence.pk}})">Annehmen</button>
</div>
</form>
<script type="text/javascript">
absencestring_confirm = 'Sicher, dass Sie die Abwesenheit für {{absence.user.first_name}} {{absence.user.last_name}} vom {{absence.start|date:"d.m Y"}} bis {{absence.end|date:"d.m Y"}} <b>annehmen</b> wollen?'
absencestring_noconfirm = 'Sicher, dass Sie die Abwesenheit für {{absence.user.first_name}} {{absence.user.last_name}} vom {{absence.start|date:"d.m Y"}} bis {{absence.end|date:"d.m Y"}} <b>ablehnen</b> wollen?'
</script>

View File

@ -1,18 +1,17 @@
{% load counter_tag %}
<div class="btn-group mr-2 mb-2" role="group" aria-label="calendarbuttons">
<button type="button" class="btn btn-primary mr-1" onclick="javascript:prevMonth()" ><i class="fas fa-arrow-circle-left"></i></button>
<button type="button" class="btn btn-primary mr-1" style="min-width: 150px !important;">{{days_this_month.0|date:"F Y"}}</button>
<button type="button" class="btn btn-primary mr-1" onclick="javascript:nextMonth()"><i class="fas fa-arrow-circle-right"></i></button>
</div>
<table class="table table-striped table-sm table-bordered" id="timetable_team">
<th>
{% for da in days_this_month %}
<tr>
<td id="9999999999_tableheadid">
<div class="btn-group ml-3 mb-2 mt-2" role="group" aria-label="calendarbuttons">
<button type="button" class="btn btn-primary mr-1" onclick="javascript:prevMonth()" ><i class="fas fa-arrow-circle-left"></i></button>
<button type="button" class="btn btn-primary mr-1" style="min-width: 150px !important;" onclick="javascript:fastChangeModal()">{{days_this_month.0|date:"F Y"}}</button>
<button type="button" class="btn btn-primary mr-1" onclick="javascript:nextMonth()"><i class="fas fa-arrow-circle-right"></i></button>
</div>
</td>
{% for da in days_this_month %}
<td id="{{forloop.counter0}}_tableheadid"><small>{{da|date:"d D"}}</small></td>
{% endfor %}
</th>
</tr>
{% for us in usersofagency %}
{% setdateforloopcounter forloop.counter %}
@ -27,12 +26,72 @@
{% isfreeday user da as isfree %}
{% isfreedayname user da as isfreename %}
{% if isfree %}
<td id="{{actfcounter}}_{{forloop.counter}}_{{us.pk}}_free" style="background-color: #e74a3b" data-toggle="tooltip" data-placement="top" title="{{isfreename}}">
{% getabscenceday user us da as abday %}
{% if isfree %}
<!-- FREEDAYS -->
<td id="{{actfcounter}}_{{forloop.counter}}_{{us.pk}}_free" style="background-color: #e74a3b" data-toggle="tooltip" data-placement="top" title="{{isfreename}}">
{% elif da.weekday == 5 or da.weekday == 6 %}
<td id="{{actfcounter}}_{{forloop.counter}}_{{us.pk}}_free" style="background-color: #d3d3d3">
{% else %}
<!-- WEEKEND -->
<td id="{{actfcounter}}_{{forloop.counter}}_{{us.pk}}_free" style="background-color: #d3d3d3">
{% elif abday != False %}
<!-- USER IS NOT THERE -->
{% if abday.confirm_status == 0 %}
{% if user|usergperm:"absencemanager" %}
<td id="{{actfcounter}}_{{forloop.counter}}_{{us.pk}}_{{abday.pk}}_absence"
{% if abday.start_ishalf and abday.start.day == da.day %}
class="partialfilling negative"
style="background-size: 50% 100%"
{% elif abday.end_ishalf and abday.end.day == da.day %}
class="partialfilling"
style="background-size: 50% 100%"
{% else %}
style="background-color: #36b9cc"
{% endif %}
data-toggle="tooltip" data-placement="top" title="{{abday.reason.name}} {% if abday.representator != None %} | Vertreten durch {{abday.representator.first_name}} {{abday.representator.last_name}} {% endif %} ">
{% else %}
<td id="{{actfcounter}}_{{forloop.counter}}_{{us.pk}}_{{abday.pk}}_absence"
{% if abday.start_ishalf and abday.start.day == da.day %}
class="partialfilling negative"
style="background-size: 50% 100%"
{% elif abday.end_ishalf and abday.end.day == da.day %}
class="partialfilling"
style="background-size: 50% 100%"
{% else %}
style="background-color: #36b9cc"
{% endif %} data-toggle="tooltip" data-placement="top" title="Abwesend {% if abday.representator != None %} | Vertreten durch {{abday.representator.first_name}} {{abday.representator.last_name}} {% endif %} ">
{% endif %}
{% elif abday.confirm_status == 1 %}
{% if user|usergperm:"absencemanager" %}
<td id="{{actfcounter}}_{{forloop.counter}}_{{us.pk}}_{{abday.pk}}_absencetoc"
{% if abday.start_ishalf and abday.start.day == da.day %}
class="partialfilling_nf negative_nf"
style="background-size: 50% 100%"
{% elif abday.end_ishalf and abday.end.day == da.day %}
class="partialfilling_nf"
style="background-size: 50% 100%"
{% else %}
style="background-color: #858796"
{% endif %}
data-toggle="tooltip" data-placement="top" title="Nicht bestätigt | {{abday.reason.name}} {% if abday.representator != None %} | Vertreten durch {{abday.representator.first_name}} {{abday.representator.last_name}} {% endif %} ">
{% else %}
<td id="{{actfcounter}}_{{forloop.counter}}_{{us.pk}}_{{abday.pk}}_absencetoc"
{% if abday.start_ishalf and abday.start.day == da.day %}
class="partialfilling_nf negative_nf"
style="background-size: 50% 100%"
{% elif abday.end_ishalf and abday.end.day == da.day %}
class="partialfilling_nf"
style="background-size: 50% 100%"
{% else %}
style="background-color: #858796"
{% endif %} data-toggle="tooltip" data-placement="top" title="Nicht bestätigt | Abwesend {% if abday.representator != None %} | Vertreten durch {{abday.representator.first_name}} {{abday.representator.last_name}} {% endif %}">
{% endif %}
{% else %}
<td id="{{actfcounter}}_{{forloop.counter}}_{{us.pk}}_{{da|date:'Y-m-d'}}" {% if us.pk == user.pk or user|usergperm:"absencemanager" %}class="tm-ab-tdhover"{% endif %}>
{% endif %}
{% else %}
<!-- NORMAL CHOICE -->
<td id="{{actfcounter}}_{{forloop.counter}}_{{us.pk}}_{{da|date:'Y-m-d'}}" {% if us.pk == user.pk or user|usergperm:"absencemanager" %}class="tm-ab-tdhover"{% endif %}>
{% endif %}
</td>
@ -40,26 +99,123 @@
</tr>
{% endfor %}
</table>
<style type="text/css">
.partialfilling {
background-image: linear-gradient(to right, #36b9cc 0%, #36b9cc 17%, #36b9cc 33%, #36b9cc 67%, #36b9cc 83%, #36b9cc 100%); /* your gradient */
background-repeat: no-repeat; /* don't remove */
}
.partialfilling.negative {
background-image: linear-gradient(to left, #36b9cc 0%, #36b9cc 17%, #36b9cc 33%, #36b9cc 67%, #36b9cc 83%, #36b9cc 100%); /* your gradient */
background-position: 100% 100%;
}
.partialfilling_nf {
background-image: linear-gradient(to right, #858796 0%, #858796 17%, #858796 33%, #858796 67%, #858796 83%, #858796 100%); /* your gradient */
background-repeat: no-repeat; /* don't remove */
}
.partialfilling_nf.negative_nf {
background-image: linear-gradient(to left, #858796 0%, #858796 17%, #858796 33%, #858796 67%, #858796 83%, #858796 100%); /* your gradient */
background-position: 100% 100%;
}
</style>
<script type="text/javascript">
<div class="modal fade" tabindex="-1" id="fastjumpmodal" data-backdrop="static">
<div class="modal-dialog" role="document">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title">Zeitraum auswählen</h5>
<button type="button" class="close" data-dismiss="modal" aria-label="Close">
<span aria-hidden="true">&times;</span>
</button>
</div>
<div class="modal-body">
<div class="form-group">
<label for="exampleFormControlSelect1">Jahr auswählen</label>
{% getsomeyears activeyear as years %}
<select class="form-control" id="choosenyear">
{% for y in years %}
<option val="{{y}}" {% if y == activeyear %} selected{% endif%}>{{y}}</option>
{% endfor %}
</select>
</div>
{% getsomemonths as months %}
{% for m in months %}
<button class="btn
{% if forloop.counter == activemonth %} btn-secondary {% else %} btn-primary {% endif %}
btn-sm mr-2 mb-2" onclick="javascript:goFastToMonth({{forloop.counter}})">{{m}}</button>
{% endfor %}
</div>
<div class="modal-footer">
<button type="button" class="btn btn-secondary" data-dismiss="modal">Schließen</button>
</div>
</div>
</div>
</div>
<script type="text/javascript">
var choosenyear = "{{activeyear}}";
function goFastToMonth(month){
location.href = "/tm/abs/" + month +"/" + choosenyear
}
document.getElementById("choosenyear").addEventListener("change", function(){
choosenyear = $('#choosenyear :selected').val();
})
$(function () {
$('[data-toggle="tooltip"]').tooltip()
})
function fastChangeModal(){
$("#fastjumpmodal").modal("toggle");
}
//Set required repr or not
document.getElementById("id_reason").addEventListener("change", function(){
reasonid = $('#id_reason :selected').val();
//Get required-rep
$.ajax(
{
type: "GET",
url: "{% url 'tm-ajax' %}",
data:{
action : "checkrequired",
rid : reasonid
},
success : function(data){
if(data["isreq"]){
$("#id_representator").prop('required',true);
$("label[for*='id_representator']").html("Vertreter*");
}
else{
$("#id_representator").prop('required',false);
$("label[for*='id_representator']").html("Vertreter");
}
}
});
})
$("#id_activemonth").val("{{activemonth}}")
$("#id_activeyear").val("{{activeyear}}")
$("#id_prevmonth").val("{{prevmonth}}")
$("#id_nextmonth").val("{{nextmonth}}")
$("#id_prevyear").val("{{prevyear}}")
$("#id_nextyear").val("{{nextyear}}")
function prevMonth(){
$.ajax({
$.ajax(
{
type: "GET",
url: "{% url 'tm-ajax' %}",
data:{
action : "testdjango",
action : "getrenderedtable",
activeyear : {{prevyear}},
activemonth : {{prevmonth}}
},
@ -69,9 +225,9 @@ function prevMonth(){
},
success : function(data){
$("#overlay").fadeOut();
$("#rendered_table").html(data)
$("#rendered_table").html(data);
}
});
});
}
function nextMonth(){
@ -79,7 +235,7 @@ function nextMonth(){
type: "GET",
url: "{% url 'tm-ajax' %}",
data:{
action : "testdjango",
action : "getrenderedtable",
activeyear : {{nextyear}},
activemonth : {{nextmonth}}
},
@ -106,7 +262,6 @@ else{
}
function recalculateChoosenDays(){
seldates = [];
userid = "";
@ -119,6 +274,7 @@ function recalculateChoosenDays(){
date_end = new Date(seldates[seldates.length-1])
$("#div_id_end").show();
$("#div_id_end_ishalf").show();
$("#startAbsenceProgress").modal("toggle");
$("#id_start").data("DateTimePicker").date(date_start);
@ -126,10 +282,11 @@ function recalculateChoosenDays(){
if(seldates.length == 1){
$("#div_id_end").hide();
$("#div_id_end_ishalf").hide();
}
}
$( function() {
$( "#timetable_team" ).selectable({
filter: 'td',
@ -140,16 +297,79 @@ $( function() {
},
selecting: function(event, ui){
newid = ui["selecting"]["id"];
if(newid.split("_")[1] == "tableheadid" || newid.split("_")[3] == "firstcolum" || (newid.split("_")[2] != {{user.pk}} && user_has_right != true ) || newid.split("_")[3] == "free"){
$("#" + newid).removeClass();
if(newid.split("_")[1] == "tableheadid" || newid.split("_")[3] == "firstcolum" || (newid.split("_")[2] != {{user.pk}} && user_has_right != true ) || newid.split("_")[3] == "free" || newid.split("_")[4] == "absence"){
if($("#" + newid).hasClass("negative")){
$("#" + newid).removeClass();
$("#" + newid).addClass("partialfilling");
$("#" + newid).addClass("negative");
}
else if($("#" + newid).hasClass("partialfilling"))
{
$("#" + newid).removeClass();
$("#" + newid).addClass("partialfilling");
}
else if($("#" + newid).hasClass("negative_nf")){
$("#" + newid).removeClass();
$("#" + newid).addClass("partialfilling_nf");
$("#" + newid).addClass("negative_nf");
}
else if($("#" + newid).hasClass("partialfilling_nf"))
{
$("#" + newid).removeClass();
$("#" + newid).addClass("partialfilling_nf");
}
else{
$("#" + newid).removeClass();
}
}
else if(newid.split("_")[4] == "absencetoc"){
if($("#" + newid).hasClass("negative")){
$("#" + newid).removeClass();
$("#" + newid).addClass("partialfilling");
$("#" + newid).addClass("negative");
}
else if($("#" + newid).hasClass("partialfilling"))
{
$("#" + newid).removeClass();
$("#" + newid).addClass("partialfilling");
}
else if($("#" + newid).hasClass("negative_nf")){
$("#" + newid).removeClass();
$("#" + newid).addClass("partialfilling_nf");
$("#" + newid).addClass("negative_nf");
}
else if($("#" + newid).hasClass("partialfilling_nf"))
{
$("#" + newid).removeClass();
$("#" + newid).addClass("partialfilling_nf");
}
else{
$("#" + newid).removeClass();
}
idtoopen = newid.split("_")[3];
openModalABChangeTable(idtoopen);
}
else{
if(selectedElements.length == 0){
active_row = newid.split("_")[0];
selectedElements.push(ui["selecting"]["id"]);
}
else if(newid.split("_")[0] != active_row){
$("#" + newid).removeClass();
else if(newid.split("_")[0] != active_row){
if($("#" + newid).hasClass("negative")){
$("#" + newid).removeClass();
$("#" + newid).addClass("partialfilling");
$("#" + newid).addClass("negative");
}
else if($("#" + newid).hasClass("partialfilling"))
{
$("#" + newid).removeClass();
$("#" + newid).addClass("partialfilling");
}
else{
$("#" + newid).removeClass();
}
}
else{
selectedElements.push(ui["selecting"]["id"]);
@ -160,48 +380,21 @@ $( function() {
selectedElements.splice(selectedElements.indexOf(ui["unselecting"]["id"]),1);
},
stop: function(){
recalculateChoosenDays();
//Selection ends, check if elements set and open modal
if(selectedElements.length > 0){
$("#timetable_team tbody tr").each(function(i) {
// find the first td in the row
var value = $(this).find("td:first").text();
// display the value in console
checkrow = parseInt(active_row)
if(i == (checkrow)){
$("#username_abscence").html(value);
$("#id_userid").val(selectedElements[0].split("_")[2])
}
});
recalculateChoosenDays();
}
}
});
} );
</script>
<style>
.loader {
position: relative;
border: 7px solid #d3d3d3;
border-radius: 50%;
border-top: 7px solid red;
width: 70px;
height: 70px;
left:50%;
top:50%;
-webkit-animation: spin 1s linear infinite; /* Safari */
animation: spin 1s linear infinite;
}
#overlay{
position: absolute;
top:0px;
left:0px;
width: 100%;
height: 100%;
background: black;
opacity: .4;
}
.container{
position:relative;
height: 300px;
width: 200px;
border:1px solid red;
}
/* Safari */
@-webkit-keyframes spin {
0% { -webkit-transform: rotate(0deg); }
100% { -webkit-transform: rotate(360deg); }
}
@keyframes spin {
0% { transform: rotate(0deg); }
100% { transform: rotate(360deg); }
}
</style>

View File

@ -68,7 +68,7 @@
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
Arbeitstag löschen
<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?

View File

@ -0,0 +1,93 @@
<div class="row col-12 mt-3" >
<div class="table-responsive">
<table class="table table-hover" id="table_allabsences">
<thead>
<tr>
<th scope="col">Mitarbeiter</th>
<th scope="col">Start</th>
<th scope="col">Ende</th>
<th scope="col">Grund</th>
<th scope="col">Info</th>
<th scope="col">Status</th>
<th scope="col">&nbsp;</th>
</tr>
</thead>
<tbody id="">
{% for abday in allabsences %}
<tr id="tableele_ab_{{abday.pk}}">
<td>{{abday.user.first_name}} {{abday.user.last_name}}</td>
<td>{{abday.start|date:"d.M Y"}}</td>
<td>{{abday.end|date:"d.M Y"}}</td>
<td>{{abday.reason.name}}</td>
<td>{{abday.info}}</td>
<td>{% if abday.confirm_status == 0 %} Genehmigt {% elif abday.confirm_status == 1 %} Beantragt {% else %} Abgelehnt {% endif %}</td>
<td>
<button type="button " class="btn btn-secondary btn-sm" onclick="javascript:$('#confirm-delete_{{abday.pk}}').modal('toggle')"><i class="fas fa-trash"></i></button>
</td>
</tr>
{% endfor %}
</tbody>
</table>
</div>
</div>
<script type="text/javascript">
$(document).ready(function(){
$('#table_allabsences').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>
{% for ab in allabsences %}
<div class="modal fade" id="confirm-delete_{{ab.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">Abwesenheit löschen</h5>
</div>
<div class="modal-body">
Möchten Sie wirklich die Abwesenheit von {{ab.user.first_name}} {{ab.user.last_name}} vom {{ab.start|date:"d.m.Y"}} bis {{ab.end|date:"d.m.Y"}} löschen?
</div>
<div class="modal-footer">
<button class="btn btn-danger" id="ab_{{ab.pk}}" >Löschen</button>
<button type="button" class="btn btn-success" data-dismiss="modal">Abbrechen</button>
</div>
</div>
</div>
</div>
<script type="text/javascript">
$("#ab_{{ab.pk}}").click(function(){
$.ajax(
{
type: "GET",
url: "{% url 'tm-ajax' %}",
data:{
action : "remove_absence",
ab: {{ab.pk}},
},
success: function( data )
{
location.href = "{% url 'tma-management' activemonth activeyear %}"
}
});
});
</script>
{% endfor %}

View File

@ -3,48 +3,143 @@
{% load crispy_forms_tags %}
{% load counter_tag %}
{% if request.user.profile.agency.module_timemanagement_ze %}
<!-- Moment.js -->
<script src="https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.23.0/moment.min.js" integrity="sha256-VBLiveTKyUZMEzJd6z2mhfxIqz3ZATCuVMawPZGzIfA=" crossorigin="anonymous"></script>
<!-- Tempus Dominus Bootstrap 4 -->
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/tempusdominus-bootstrap-4/5.1.2/css/tempusdominus-bootstrap-4.min.css" integrity="sha256-XPTBwC3SBoWHSmKasAk01c08M6sIA5gF5+sRxqak2Qs=" crossorigin="anonymous" />
<script src="https://cdnjs.cloudflare.com/ajax/libs/tempusdominus-bootstrap-4/5.1.2/js/tempusdominus-bootstrap-4.min.js" integrity="sha256-z0oKYg6xiLq3yJGsp/LsY9XykbweQlHl42jHv2XTBz4=" crossorigin="anonymous"></script>
<link rel="stylesheet" href="//code.jquery.com/ui/1.12.1/themes/base/jquery-ui.css">
<div class="content-section col-12">
<h3>Abwesenheiten{% if request.user.profile.showtooltips %}&nbsp;<small><i data-toggle="tooltip" data-placement="top" title="Bearbeiten Sie hier Ihre Abwesenheiten." class="far fa-question-circle"></i></small>{% endif %}</h3>
<hr>
<div>
<div id="rendered_table">
Lade Kalenderdaten...
</div>
<div id="overlay" style="display: none;">
<div class="loader"></div>
<ul class="nav nav-tabs" id="absencetabs" role="tablist">
<li class="nav-item">
<a class="nav-link active" id="team-tab" data-toggle="tab" href="#team" role="tab" aria-controls="team" aria-selected="false">Teamübersicht</a>
</li>
<li class="nav-item">
<a class="nav-link" id="userown-tab" data-toggle="tab" href="#userown" role="tab" aria-controls="userown" aria-selected="false">Meine Abwesenheiten</a>
</li>
{% if user|usergperm:"absencemanager" %}
<li class="nav-item ">
<a class="nav-link" id="absencemanagercontent-tab" data-toggle="tab" href="#absencemanagercontent" role="tab" aria-controls="absencemanagercontent" aria-selected="false">
{% if needtoconfirm|length > 0 %}
<span class="badge badge-primary badge-counter" style="float: right; margin-left: 5px; margin-top: 0px">{{needtoconfirm|length}} </span>&nbsp;
{%endif%}
Ausstehende Anträge
</a>
</li>
<li class="nav-item ">
<a class="nav-link" id="absencemanagercontent_all-tab" data-toggle="tab" href="#absencemanagercontent_all" role="tab" aria-controls="absencemanagercontent_all" aria-selected="false">
Alle Abwesenheiten
</a>
</li>
{% endif %}
</ul>
<div class="tab-content" id="absencetabsContent">
<div class="tab-pane fade" id="team" role="tabpanel" aria-labelledby="team-tab">
<div>
<div id="rendered_table">
Lade Kalenderdaten...
</div>
</div>
</div>
<div class="tab-pane fade" id="userown" role="tabpanel" aria-labelledby="team-tab">
{% block ab_userown %}
{% include "timemanagement/tm_ab_userown.html" %}
{% endblock %}
</div>
{% if user|usergperm:"absencemanager" %}
<div class="tab-pane fade" id="absencemanagercontent" role="tabpanel" aria-labelledby="team-tab">
{% block ab_toconfirm %}
{% include "timemanagement/tm_ab_toconfirm.html" %}
{% endblock %}
</div>
<div class="tab-pane fade" id="absencemanagercontent_all" role="tabpanel" aria-labelledby="team-tab">
{% block ab_all %}
{% include "timemanagement/tm_ab_all.html" %}
{% endblock %}
</div>
{% endif %}
</div>
</div>
<!-- LOADER OVERLAY -->
<div id="overlay" style="display: none;">
<div class="loader"></div>
</div>
<!-- MODAL -->
<div class="modal fade" tabindex="-1" role="dialog" id="startAbsenceProgress" data-backdrop="static">
<div class="modal-dialog" role="document">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title">Abwesenheit bentragen</h5>
<h5 class="modal-title">Abwesenheit beantragen</h5>
<button type="button" class="close" data-dismiss="modal" aria-label="Close">
<span aria-hidden="true">&times;</span>
</button>
</div>
<div class="modal-body">
<h5>Abwesenheit für <b><span id="username_abscence"></span></b> beantragen</h5>
<hr>
<form method="POST">
<input type="hidden" name="form_type" value="absenceform">
{% csrf_token %}
{{abscenceform.media}}
{{abscenceform|crispy}}
</form>
{{abscenceform|crispy}}
</div>
<div class="modal-footer">
<button type="button" class="btn btn-primary">Abwesenheit beantragen</button>
<button type="submit" class="btn btn-primary">Abwesenheit beantragen</button>
<button type="button" class="btn btn-secondary" data-dismiss="modal">Abbrechen</button>
</div>
</form>
</div>
</div>
</div>
<!-- MODAL -->
<div class="modal fade" tabindex="-1" id="updateAbsenceToConfirm" data-backdrop="static">
<div class="modal-dialog" role="document">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title">Abwesenheitsantrag</h5>
<button type="button" class="close" data-dismiss="modal" aria-label="Close">
<span aria-hidden="true">&times;</span>
</button>
</div>
<div class="modal-body">
<div id="confirmcontent"></div>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-secondary" data-dismiss="modal" onclick="javascript:closeOnly()">Schließen</button>
</div>
</div>
</div>
</div>
<div class="modal fade" tabindex="-1" id="updateAbsenceToConfirmSecond" data-backdrop="static">
<div class="modal-dialog" role="document">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title">Abwesenheitsantrag</h5>
<button type="button" class="close" data-dismiss="modal" aria-label="Close">
<span aria-hidden="true">&times;</span>
</button>
</div>
<div class="modal-body">
<div id="confirmcontentsecond"></div>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-primary" onclick="javascript:confirmAbscenceFinal()">Bestätigung</button>
<button type="button" class="btn btn-secondary" data-dismiss="modal">Abbrechen</button>
</div>
</div>
</div>
</div>
<style>
.tm-ab-tdhover:hover{
background-color: #858796 !important;
@ -78,20 +173,142 @@
<style>
/* DATATABLES */
.paginate_button {
padding: 0px !important;
border: 0px !important;
}
</style>
<style>
.loader {
position: relative;
border: 7px solid #d3d3d3;
border-radius: 50%;
border-top: 7px solid red;
width: 70px;
height: 70px;
left:50%;
top:35%;
-webkit-animation: spin 1s linear infinite; /* Safari */
animation: spin 1s linear infinite;
}
#overlay{
position: absolute;
top:0px;
left:0px;
width: 100%;
height: 100%;
background: black;
opacity: .4;
}
.container{
position:relative;
height: 300px;
width: 200px;
border:1px solid red;
}
/* Safari */
@-webkit-keyframes spin {
0% { -webkit-transform: rotate(0deg); }
100% { -webkit-transform: rotate(360deg); }
}
@keyframes spin {
0% { transform: rotate(0deg); }
100% { transform: rotate(360deg); }
}
</style>
<script>
//Initial Load
function loaddjango(){
var absencetowork = "";
var absencestring_confirm = "";
var absencestring_noconfirm = "";
var newconfstat = "";
var closeonly = false;
function closeOnly(){
closeonly = true;
}
function confirmAbscenceFinal(){
$.ajax({
type: "GET",
url: "{% url 'tm-ajax' %}",
data:{
action : "testdjango",
action : "confirmornotabscence",
absencetowork : absencetowork,
newconfstat : newconfstat,
info : $("#id_confirm_info").val(),
activemonth : $("#id_activemonth").val(),
activeyear : $("#id_activeyear").val(),
},
success : function(data){
location.href = "/tm/abs/" + data["activemonth"] +"/" + data["activeyear"]
}
});
}
function openModalABChangeTable(idtopen){
closeonly = false;
absencetowork = idtopen;
$.ajax({
type: "GET",
url: "{% url 'tm-ajax' %}",
data:{
action : "getrenderedform",
abscenceid : idtopen
},
beforeSend: function(request) {
request.setRequestHeader("X-Requested-With", "XMLHttpRequest");
},
success : function(data){
$("#confirmcontent").html(data);
$("#updateAbsenceToConfirm").modal("show");
}
});
}
function noconfirmAbsence(id){
newconfstat = 2;
$("#updateAbsenceToConfirm").modal("toggle");
$('#updateAbsenceToConfirm').on('hidden.bs.modal', function () {
if(closeonly == false){
$("#updateAbsenceToConfirmSecond").modal("toggle");
$("#confirmcontentsecond").html(absencestring_noconfirm);
}
});
}
function confirmAbsence(id){
newconfstat = 0;
$("#updateAbsenceToConfirm").modal("toggle");
$('#updateAbsenceToConfirm').on('hidden.bs.modal', function () {
if(closeonly == false){
$("#updateAbsenceToConfirmSecond").modal("toggle");
$("#confirmcontentsecond").html(absencestring_confirm);
}
});
}
//Initial Load
function loaddjango(){
$("#id_activemonth").val("{{activemonth}}")
$("#id_activeyear").val("{{activeyear}}")
$("#id_prevmonth").val("{{prevmonth}}")
$("#id_nextmonth").val("{{nextmonth}}")
$("#id_prevyear").val("{{prevyear}}")
$("#id_nextyear").val("{{nextyear}}")
$.ajax({
type: "GET",
url: "{% url 'tm-ajax' %}",
data:{
action : "getrenderedtable",
activeyear : {{activeyear}},
activemonth : {{activemonth}}
},
@ -101,14 +318,46 @@ function loaddjango(){
success : function(data){
$("#rendered_table").html(data)
}
});
});
}
$(document).ready(function(){
loaddjango();
moment.locale('de');
loaddjango();
var activeTab = localStorage.getItem('activeTabAbsence');
if(activeTab){
if($('#' + activeTab).find().prevObject.length != 0){
$('#' + activeTab).tab('show');
$(".nav-link").removeClass("active");
$("#" + activeTab + "-tab").addClass("active");
}
else{
$("#team-tab").addClass("active");
$('#team').tab('show');
}
}
else{
$("#team-tab").addClass("active");
$('#team').tab('show');
}
});
$('#absencetabs a').on('click', function (e) {
e.preventDefault();
lastview_name = $(this)[0]['hash'].substring(1);
localStorage.setItem('activeTabAbsence', lastview_name);
});
</script>
{% else %}
<h3>Das Modul Abwesenheits- und Zeiterfassung wurde in ihrer Agentur deaktiviert.</h3>

View File

@ -0,0 +1,57 @@
{% load counter_tag %}
<div class="row col-12 mt-3" >
<div class="table-responsive">
<table class="table table-hover" id="table_toconfirmab">
<thead>
<tr>
<th scope="col">Mitarbeiter</th>
<th scope="col">Start</th>
<th scope="col">Ende</th>
<th scope="col">Grund</th>
<th scope="col">Info</th>
<th scope="col">Status ändern</th>
</tr>
</thead>
<tbody id="">
{% for abday in needtoconfirm %}
<tr>
<td>{{abday.user.first_name}} {{abday.user.last_name}}</td>
<td>{{abday.start|date:"d.M Y"}}</td>
<td>{{abday.end|date:"d.M Y"}}</td>
<td>{{abday.reason.name}}</td>
<td>{{abday.info}}</td>
<td>
<button type="button " class="btn btn-secondary btn-sm" onclick='javascript:openModalABChangeTable({{abday.pk}})'><i class="fas fa-eye"></i></button>
</td>
</tr>
{% endfor %}
</tbody>
</table>
</div>
</div>
<script type="text/javascript">
$(document).ready(function(){
$('#table_toconfirmab').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>

View File

@ -0,0 +1,50 @@
<div class="row col-12 mt-3" >
<div class="table-responsive">
<table class="table table-hover" id="table_userownab">
<thead>
<tr>
<th scope="col">Start</th>
<th scope="col">Ende</th>
<th scope="col">Grund</th>
<th scope="col">Status</th>
<th scope="col">Begründung</th>
</tr>
</thead>
<tbody id="">
{% for abday in userown %}
<tr>
<td>{{abday.start|date:"d.M Y"}}</td>
<td>{{abday.end|date:"d.M Y"}}</td>
<td>{{abday.reason.name}}</td>
<td>{% if abday.confirm_status == 0 %} Genehmigt {% elif abday.confirm_status == 1 %} Beantragt {% else %} Abgelehnt {% endif %}</td>
<td>{{abday.confirm_info}}</td>
</tr>
{% endfor %}
</tbody>
</table>
</div>
</div>
<script type="text/javascript">
$(document).ready(function(){
$('#table_userownab').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>

View File

@ -1,7 +1,7 @@
from django.shortcuts import render
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
from .models import Workday, Breaks, FreeDays, AbsenceReason, Absence
from django.utils import timezone
import requests, csv, os
from django.templatetags.static import static
@ -11,7 +11,11 @@ from django.contrib.auth.models import User
from calendar import monthrange
import datetime
import calendar
from .forms import AddAbsence
from .forms import AddAbsence, ConfirmAbsenceForm
from django.contrib import messages
from users.models import UserFullName
def loadingFreeDays(plz):
# Getting land
@ -46,70 +50,124 @@ def get_datetime_range(year, month):
@login_required
def AbsenceManagmenet(request, activemonth=False, activeyear=False):
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
# 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("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:
nextmonth = activemonth + 1
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
if(activemonth == 1):
prevmonth = 12
else:
prevmonth = activemonth-1
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,
"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(activemonth == 12):
nextmonth = 1
else:
nextmonth = activemonth + 1
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")
})
#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
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,
"prevmonth" : prevmonth,
"nextyear" : nextyear,
"prevyear" : prevyear,
"activemonth" : activemonth,
"activeyear" : activeyear,
"abscenceform" : AddAbsence()
}
return render(request, 'timemanagement/tm_ab_management.html', context)
return render(request, 'timemanagement/tm_ab_management.html', context)
@login_required
def TimeManagement(request):
def TimeManagement(request):
context = {
"active_link" : "timemanagement",
"workdays" : Workday.objects.filter(agency=request.user.profile.agency, user=request.user).order_by("-start")
@ -187,8 +245,8 @@ def TimeAjax(request):
}
else:
data = { "success" : False}
# REMOVE WORKDAY
elif request.GET["action"] == "testdjango":
# Get Rendered Table
elif request.GET["action"] == "getrenderedtable":
prevmonth = ""
nextmonth = ""
activemonth = int(request.GET["activemonth"])
@ -248,9 +306,57 @@ def TimeAjax(request):
"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
}
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"]
}
else:
data = {
"success" : False
@ -258,3 +364,4 @@ def TimeAjax(request):
return JsonResponse(data)

View File

@ -6,7 +6,7 @@ from django.contrib.auth.models import Permission
from message.models import Message
from cloud.models import DataFile
from organizer.models import AGContacts
from timemanagement.models import Workday, Breaks, AbsenceReason, FreeDays
from timemanagement.models import Workday, Breaks, AbsenceReason, FreeDays, Absence
admin.site.register(StandardComments)
admin.site.register(StandardCommentRate)
@ -25,4 +25,5 @@ admin.site.register(UserTime)
admin.site.register(Workday)
admin.site.register(Breaks)
admin.site.register(AbsenceReason)
admin.site.register(Absence)
admin.site.register(FreeDays)

View File

@ -252,7 +252,9 @@ class UserTime(models.Model):
wd_th = models.FloatField(default=8.0)
wd_fr = models.FloatField(default=8.0)
holiday = models.FloatField(default=24.0)
loose_holidedate = models.DateField(default=datetime.date(datetime.datetime.now().year + 1, 4,30))
holiday_start = models.FloatField(default=0.0)
loose_holidedate = models.DateField(default=datetime.date(datetime.datetime.now().year + 1, 4,30))
startdate = models.DateTimeField(default=None, blank=True, null=True)
'''

Binary file not shown.

Before

Width:  |  Height:  |  Size: 456 KiB

After

Width:  |  Height:  |  Size: 149 KiB