Abwesenheit und Chat

This commit is contained in:
Holger Trampe 2020-05-22 01:55:48 +02:00
parent a00710e04c
commit 15348b2d25
33 changed files with 963 additions and 149 deletions

View File

@ -1,3 +1,4 @@
{% load counter_tag %}
{% if roomdata.creator == user %}
<h4 id="chattitle">Gespräch mit {{roomdata.chatmember_single.first_name}} {{roomdata.chatmember_single.last_name}}</h4>
{% else %}
@ -8,43 +9,57 @@
<div class="card" >
<div class="card-body scroll" id="chatcontentcomplete">
<div id="roomstart" style="min-width: 100%; text-align: center;">
<small>Unterhaltung gestartet am {{roomdata.chatroom_createddate}}</small>
<div id="roomstart" style="min-width: 100%; text-align: center;">
<small>Unterhaltung gestartet am {{roomdata.chatroom_createddate}}</small>
</div>
<hr>
<div id="chatmessages">
{% for message in roomdata.messages.all %}
{% if forloop.counter0 == 0 %}
{% setMessageDayInfo message %}
{% else %}
{% getMessageDayInfo message as newday %}
{% if newday == True %}
<div style="" class="chatmessageele_breaker col-12 mb-3">
<div class="col-12 mb-3" style="text-align: center;">
<hr>
<small>{{message.sendtime|date:"d.m.Y"}}</small>
</div>
</div>
{% endif %}
{% endif %}
{% for message in roomdata.messages.all %}
{% if message.author == request.user %}
<div style="" class="chatmessageele_me col-7 mb-3 ">
<div class='icon-container ml-2 mt-1 ' style="float: right;">
<img class="img-profile roundimg" src="{{ message.author.profile.get_photo_url }}">
</div>
<h6 class="mt-3"><small>{{message.author.first_name}} {{message.author.last_name}},&nbsp;{{message.sendtime}}</small></h6>
</div>
<h6 class="mt-3"><small>{{message.sendtime|date:"H:m"}}</small></h6>
<div style="text-align: left;" class="mt-1">
<span style="float: right !important; font-size: 1.0em;">
{{message.content}}
</span>
</div>
{{message.content}}
</span>
</div>
</div>
{% else %}
<div style="" class="chatmessageele_other col-7 mb-3">
<div class='icon-container mr-2 mt-1 ' style="float: left;">
<img class="img-profile roundimg" src="{{ message.author.profile.get_photo_url }}">
</div>
<h6 class="mt-3"><small>{{message.author.first_name}} {{message.author.last_name}},&nbsp;{{message.sendtime}}</small></h6>
<div style="text-align: left;" class="mt-1">
<span style="float: left !important; font-size: 1.0em;">
{{message.content}}
</span>
<div class='icon-container mr-2 mt-1 ' style="float: left;">
<img class="img-profile roundimg" src="{{ message.author.profile.get_photo_url }}">
</div>
<h6 class="mt-3"><small>{{message.author.first_name}} {{message.author.last_name}},&nbsp;{{message.sendtime|date:"H:m"}}</small></h6>
<div style="text-align: left;" class="mt-1">
<span style="float: left !important; font-size: 1.0em;">
{{message.content}}
</span>
</div>
</div>
</div>
{% endif %}
{% endfor %}
<!-- SINGLE MESSAGE -->

View File

@ -2,7 +2,7 @@
<div class='icon-container mr-2 mt-1 ' style="float: left;">
<img class="img-profile roundimg" src="{{ newmessage.author.profile.get_photo_url }}">
</div>
<h6 class="mt-3"><small>{{newmessage.author.first_name}} {{newmessage.author.last_name}},&nbsp;{{newmessage.sendtime}}</small></h6>
<h6 class="mt-3"><small>{{newmessage.author.first_name}} {{newmessage.author.last_name}},&nbsp;{{newmessage.sendtime|date:"H:m"}}</small></h6>
<div style="text-align: left;" class="mt-1">
<span style="float: left !important; font-size: 1.0em;">
{{newmessage.content}}

View File

@ -2,7 +2,7 @@
<div class='icon-container ml-2 mt-1 ' style="float: right;">
<img class="img-profile roundimg" src="{{ newmessage.author.profile.get_photo_url }}">
</div>
<h6 class="mt-3"><small>{{newmessage.author.first_name}} {{newmessage.author.last_name}},&nbsp;{{newmessage.sendtime}}</small></h6>
<h6 class="mt-3"><small>{{newmessage.sendtime|date:"H:m"}}</small></h6>
<div style="text-align: left;" class="mt-1">
<span style="float: right !important; font-size: 1.0em;">
{{newmessage.content}}

View File

@ -25,11 +25,15 @@
position: absolute;
}
.chatmessageele_breaker
{
float: right;
}
.chatmessageele_me
{
padding: 5px;
border-radius: 15px;
background-color: #f8f9fc;
background-color: #cfe6f4;
float: right;
text-align: right;
}
@ -38,10 +42,10 @@
{
padding: 5px;
border-radius: 15px;
background-color: #858796;
background-color: #f8f9fc;
float: left;
text-align: left;
color: #ffffff;
color: #000000;
}
.scroll {

View File

@ -420,7 +420,7 @@ a.disabled {
</div></div>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-success" data-dismiss="modal">Beenden</button>
<button type="button" class="btn btn-primary" data-dismiss="modal">Beenden</button>
</div>
</div>
</div>

View File

@ -5,6 +5,7 @@ from users.models import AgencyGroup, Agency, Profile, AgencyJob, AgencyNetwork,
from PIL import Image
from bootstrap_datepicker_plus import DatePickerInput
from django.utils.translation import gettext as _
from timemanagement.models import AbsenceReason
class AgencyTimeManagement(forms.ModelForm):
class Meta:
@ -71,15 +72,16 @@ class UserTimeForm(forms.ModelForm):
"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",
#"wd_mo" : "Montag",
#"wd_tu" : "Dienstag",
#"wd_we" : "Mittwoch",
#"wd_th" : "Donnerstag",
#"wd_fr" : "Freitag",
}
fields = ["startdate", "wd_mo", "wd_tu", "wd_we", "wd_th", "wd_fr", "holiday", "loose_holidedate", "holiday_start", ]
#fields = ["startdate", "wd_mo", "wd_tu", "wd_we", "wd_th", "wd_fr", "holiday", "loose_holidedate", "holiday_start", ]
fields = ["startdate", "holiday", "loose_holidedate", "holiday_start", ]
widgets = {
'loose_holidedate': DatePickerInput(options={"format":'DD.MM.', "locale":'de'}),
'loose_holidedate': DatePickerInput(options={"format":'DD.MM.YYYY', "locale":'de'}),
"startdate" : DatePickerInput(options={"format":'DD.MM.YYYY', "locale":'de'})
}
@ -117,15 +119,17 @@ class AgencyModulsForm(forms.ModelForm):
'module_files' : "Dateien",
'module_organigramm' : "Organigramm",
'module_messages' : "Mitteilungen",
'module_timemanagement' : "Abwesenheits- und Zeiterfassung",
'module_chat' : "Chat",
#'module_timemanagement' : "Abwesenheits- und Zeiterfassung",
'module_timemanagement' : "Abwesenheitsplanung",
}
fields = ['module_news','module_organizer','module_files','module_organigramm', 'module_messages', 'module_timemanagement']
fields = ['module_news','module_organizer','module_files','module_organigramm', 'module_messages', 'module_chat', 'module_timemanagement']
# RAUSNHEMEN WENN DEV DONE
def __init__(self, *args, **kwargs):
super(AgencyModulsForm, self).__init__(*args, **kwargs)
self.fields['module_timemanagement'].widget.attrs['readonly'] = True
self.fields['module_timemanagement'].widget.attrs['disabled'] = True
#self.fields['module_timemanagement'].widget.attrs['readonly'] = True
#self.fields['module_timemanagement'].widget.attrs['disabled'] = True
# NEW USER FORM
@ -187,3 +191,15 @@ class UserProfileForm(forms.ModelForm):
except:
print("no photo")
class AbsenceReasonForm(forms.ModelForm):
class Meta:
model = AbsenceReason
labels = {
"name" : "Bezeichnung",
"need_confirm" : "Muss bestätigt werden",
"need_rep" : "Muss vertreten werden",
"is_holiday" : "Geht vom Urlaub ab",
"color" : "Farbe"
}
fields = ["name", "need_confirm", "need_rep", "is_holiday", "color"]

View File

@ -0,0 +1,20 @@
{% extends "users/base.html" %}
{% load crispy_forms_tags %}
{% block content %}
{% if request.user.profile.agency.module_timemanagement %}
<div class="content-section col-6">
<h3>Abwesenheitskategorie anlegen</h3>
<hr>
<form method="POST" enctype="multipart/form-data">
{% csrf_token %}
{{ form|crispy }}
<hr>
<button type="submit" class="btn btn-primary">Abwesenheitskategorie anlegen</button>&nbsp;
<a class="btn" href="{% url 'dasettings' %} ">Abbrechen</a>
</form>
</div>
{% else %}
<h3>Das Modul Abwesenheitsplanung wurden in ihrer Agentur deaktiviert.</h3>
{% endif %}
{% endblock content %}

View File

@ -0,0 +1,23 @@
{% extends "users/base.html" %}
{% load crispy_forms_tags %}
{% block content %}
{% if request.user.profile.agency.module_timemanagement %}
<div class="content-section">
<div class="media">
<div class="media-body">
<h2 class="account-heading">Abwesenheitskategorie {{ object.name }} löschen?</h2>
<hr>
</div>
</div>
<form method="POST">
{% csrf_token %}
<div class="form-group">
<button type="submit" class="btn btn-primary">Abwesenheitskategorie löschen</button>&nbsp;
<a href="{% url 'dasettings' %}" class="btn">Abbrechen</a>
</div>
</form>
</div>
{% else %}
<h3>Das Modul Abwesenheitsplanung wurden in ihrer Agentur deaktiviert.</h3>
{% endif %}
{% endblock content %}

View File

@ -0,0 +1,20 @@
{% extends "users/base.html" %}
{% load crispy_forms_tags %}
{% block content %}
{% if request.user.profile.agency.module_timemanagement %}
<div class="content-section col-6">
<h3>Abwesenheitskategorie aktualisieren</h3>
<hr>
<form method="POST" enctype="multipart/form-data">
{% csrf_token %}
{{ form|crispy }}
<hr>
<button type="submit" class="btn btn-primary">Abwesenheitskategorie aktualisieren</button>&nbsp;
<a class="btn" href="{% url 'dasettings' %} ">Abbrechen</a>
</form>
</div>
{% else %}
<h3>Das Modul Abwesenheitsplanung wurden in ihrer Agentur deaktiviert.</h3>
{% endif %}
{% endblock content %}

View File

@ -0,0 +1,20 @@
{% extends "users/base.html" %}
{% load crispy_forms_tags %}
{% block content %}
{% if request.user.profile.agency.module_timemanagement %}
<div class="content-section col-6">
<h3>Freien Tag anlegen</h3>
<hr>
<form method="POST" enctype="multipart/form-data">
{% csrf_token %}
{{form.media}}
{{ form|crispy }}
<hr>
<button type="submit" class="btn btn-primary">Freien Tag anlegen</button>&nbsp;
<a class="btn" href="{% url 'tm-managemenetfreedays' %} ">Abbrechen</a>
</form>
</div>
{% else %}
<h3>Das Modul Abwesenheitsplanung wurden in ihrer Agentur deaktiviert.</h3>
{% endif %}
{% endblock content %}

View File

@ -0,0 +1,24 @@
{% extends "users/base.html" %}
{% load crispy_forms_tags %}
{% block content %}
{% if request.user.profile.agency.module_timemanagement %}
<div class="content-section">
<div class="media">
<div class="media-body">
<h2 class="account-heading">Freien Tag {{ object.name }} am {{ object.day|date:"d. F Y"}} löschen?</h2>
<hr>
</div>
</div>
<!-- Für das Speichern der Bilder enctype -->
<form method="POST">
{% csrf_token %}
<div class="form-group">
<button type="submit" class="btn btn-primary">Freien Tag löschen</button>&nbsp;
<a href="{% url 'tm-managemenetfreedays' %}" class="btn">Abbrechen</a>
</div>
</form>
</div>
{% else %}
<h3>Das Modul Abwesenheitsplanung wurden in ihrer Agentur deaktiviert.</h3>
{% endif %}
{% endblock content %}

View File

@ -0,0 +1,138 @@
{% extends "users/base.html" %}
{% load counter_tag %}
{% block content %}
<div class="content-section col-12">
<h3>Feiertage und Schließtage</i></b>{% if request.user.profile.showtooltips %}&nbsp;<small><i data-toggle="tooltip" data-placement="top" title="Erstellen Sie hier Feiertage und Tage, an denen Ihre Agentur generell geschlossen hat." class="far fa-question-circle"></i></small>{% endif %}
<a class="btn btn-primary btn-sm" href="{% url 'tm-freedayadd' %}" style="float: right;"><i class="fas fa-plus"></i>&nbsp;Freier Tag</a>
</h3>
<hr>
<div class="content-section col-12">
<div class="table-responsive">
<table class="table table-hover" id="fdtable">
<thead>
<tr>
<th scope="col">Name</th>
<th scope="col">Tag</th>
<!--<th scope="col">Logo</th> -->
{% if user|usergperm:"moduleorganizer" %}
<th scope="col">&nbsp;</th>
{% endif %}
</tr>
</thead>
<tbody id="table_freedays">
{% for fd in freedays %}
<tr>
<td>{{ fd.name }}</td>
<td>{{ fd.day|date:"d. F Y" }}</td>
<td>
{% if user|usergperm:"moduleorganizer" %}
<a style="float: right" class="btn btn-secondary btn-sm ml-2" href="{% url 'freeday-delete' fd.pk %}">
<small><i class="fas fa-trash"></i></small>
</a>
{% endif %}
</td>
</tr>
{% endfor %}
</tbody>
</table>
</div>
</div>
<div class="modal fade" tabindex="-1" role="dialog" id="freedays_initloadinginfo" data-backdrop="static">
<div class="modal-dialog" role="document">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title">Feiertage laden</h5>
<button type="button" class="close" data-dismiss="modal" aria-label="Close">
<span aria-hidden="true">&times;</span>
</button>
</div>
<div class="modal-body">
<p>Sie haben das Modul Abwesenheitsplanung aktiviert. Sollen die Feiertage automatisch für die Postleitzahl {{request.user.profile.agency.plz}} geladen werden?</p>
<small>Sie können Feiertage auch nachträglich laden und verändern.</small>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-primary" onclick="javascript:loadFreeDays()">Feiertage laden</button>
<button type="button" class="btn " data-dismiss="modal">Abbrechen</button>
</div>
</div>
</div>
</div>
<div class="modal fade" tabindex="-1" role="dialog" id="plz_error" data-backdrop="static">
<div class="modal-dialog" role="document">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title">Postleitzahl nicht gefunden</h5>
<button type="button" class="close" data-dismiss="modal" aria-label="Close">
<span aria-hidden="true">&times;</span>
</button>
</div>
<div class="modal-body">
<p>Die Postleitzahl Ihrer Agentur konnte nicht gefunden. Bitte gehen Sie in den Bereich Einstellungen auf den Reiter Agentur, um dort eine gültige Postleizahl zu hinterlegen.</p>
</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(){
{% if init_freedays %}
$("#freedays_initloadinginfo").modal("toggle");
{% endif %}
$('#fdtable').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"
},
},
"aaSorting": [],
"buttons" : {
"className" : "btn-danger"
}
});
})
function loadFreeDays()
{
$("#freedays_initloadinginfo").modal("hide");
$.ajax(
{
type: "GET",
url: "{% url 'dasettings-ajax' %}",
data:{
action : "initloadfreedays",
},
success: function( data )
{
if(data["success"]){
window.location.href = "{% url 'tm-managemenetfreedays' %}";
}
else{
$("#plz_error").modal("toggle");
}
}
});
}
</script>
<style>
/* DATATABLES */
.paginate_button {
padding: 0px !important;
border: 0px !important;
}
</style>
{% endblock content %}

View File

@ -1,11 +1,45 @@
{% load crispy_forms_tags %}
<form method="POST" enctype="multipart/form-data" name="updateModSettingsTM">
{% csrf_token %}
{{modsettings_tm|crispy}}
</form>
{% for ab in modsettings_tm_abcat %}
{{ab.name}}<br />
{% endfor %}
{% load counter_tag %}
<h4 >Abwesenheitskategorien{% if request.user.profile.showtooltips %}&nbsp;<small><i data-toggle="tooltip" data-placement="top" title="Bearbeiten Sie hier Ihre Abwesenheitskategorien." class="far fa-question-circle"></i></small>{% endif %}
<a class="btn btn-primary btn-sm" href="{% url 'abcat-add' %}" style="float: right;"><i class="fas fa-plus"></i>&nbsp;Kategorie</a>
</h4>
<small>&nbsp;</small>
<table class="table table-hover mt-1">
<thead>
<tr>
<th scope="col">Bezeichnung</th>
<th scope="col">Muss bestätigt werden</th>
<th scope="col">Muss vertreten werden</th>
<th scope="col">Urlaubstag</th>
<th scope="col">&nbsp;</th>
</tr>
</thead>
<tbody>
{% for ab in modsettings_tm_abcat %}
<tr>
<td><b>{{ab.name}}</b></td>
<td>{% if ab.need_confirm %} Bedarf Bestätigung {% else %} Ohne Bestätigung {% endif %}</td>
<td>{% if ab.need_rep %} Muss vertreten werden {% else %} Ohne Vertretung {% endif %}</td>
<td>{% if ab.is_holiday %} Urlaub {% endif %}</td>
<td>
{% if user|usergperm:"moduleorganizer" %}
<a style="float: right" class="btn btn-secondary btn-sm ml-2" href="{% url 'abcat-delete' ab.pk %}">
<small>
<i class="fas fa-trash"></i></small></a>
<a style="float: right" class="btn btn-secondary btn-sm " href="{% url 'abcat-update' ab.pk %}">
<small>
<i class="fas fa-pen"></i>
</small></a>
{% endif %}
</td>
</tr>
{% endfor %}
</tbody>
</table>
<small>Abwesenheitskategorien legen fest, wie sich eine Abwesenheit bzgl. Bestätigung durch einen Mitarbeiter mit entsprechenden Rechten und eines Vertretes verhält.</small>
<hr>
<a class="btn btn-primary mb-2" href="{% url 'tm-managemenetfreedays' %}">Feiertage bearbeiten</a>
<script type="text/javascript">
function updateTmSettings(){
$.ajax(

View File

@ -164,20 +164,22 @@
<form method="POST" enctype="multipart/form-data" name="usertime_basic">
{% csrf_token %}
<input type="hidden" name="form_type" value="contract">
<!--
<p>Arbeitszeiten&nbsp;<small><i data-toggle="tooltip" data-placement="top" title="Legen Sie fest, an welchen Tagen dieser Mitarbeiter wie viele Stunden arbeitet." class="far fa-question-circle"></i></small></p>
<div class="table-responsive">
<table class="table">
<tr>
<td>{{usertime_form.wd_mo|as_crispy_field}}</td>
<td>{{usertime_form.wd_tu|as_crispy_field}}</td>
<td>{{usertime_form.wd_we|as_crispy_field}}</td>
<td>{{usertime_form.wd_th|as_crispy_field}}</td>
<td>{{usertime_form.wd_fr|as_crispy_field}}</td>
<td>usertime_form.wd_mo|as_crispy_field</td>
<td>usertime_form.wd_tu|as_crispy_field</td>
<td>usertime_form.wd_we|as_crispy_field</td>
<td>usertime_form.wd_th|as_crispy_field</td>
<td>usertime_form.wd_fr|as_crispy_field</td>
</tr>
</table>
</div>
<hr style="margin-top: -20px;">
</div>
<hr style="margin-top: -20px;">
-->
<div class="col-5" >
<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}}

View File

@ -2,6 +2,7 @@ from django.urls import path
from django.contrib.auth import views as auth_views
from django.contrib.auth.decorators import login_required, permission_required
from . import views
from .views import FreeDayDeleteView, AbsenceReasonDeleteView, AbsenceReasonUpdateView, AbsenceReasonAddView
from .views import NewUserFirstStep, UserProfileUpdate, UserChangeMain
'''
Permissions definiert in models.py bei USERS und dann hier vor die View geschrieben!
@ -25,4 +26,11 @@ urlpatterns = [
#path('managnag/delfromagn/<int:agn>/<int:ag>', permission_required('users.agencynetwork')(views.DelFromAgn), name='delagfromagn'),
path('modsettings/orga/', views.ModSettingsOrga, name="modsettings-orga"),
path('modsettings/tm/', views.ModSettingsTm, name="modsettings-tm"),
path('freedaysmn/', views.FreeDaysManagemenet, name="tm-managemenetfreedays"),
path('freedaysmn/<int:initload>', views.FreeDaysManagemenet, name="tm-initload"),
path('freedayadd/', views.FreeDayAdd, name="tm-freedayadd"),
path('freedaydel/<int:pk>', FreeDayDeleteView.as_view(), name="freeday-delete"),
path('abcatdel/<int:pk>', AbsenceReasonDeleteView.as_view(), name="abcat-delete"),
path('abcatupdate/<int:pk>', AbsenceReasonUpdateView.as_view(), name="abcat-update"),
path('abcatadd/', AbsenceReasonAddView.as_view(), name="abcat-add"),
]

View File

@ -1,7 +1,7 @@
from django.shortcuts import render, redirect
from django.contrib.auth.decorators import login_required
from django.http import HttpResponseRedirect,HttpResponse, JsonResponse
from .forms import UsersSelfChangeForm, UsersNotificationForm, AgencyGroupPerms, AgencyModulsForm, UserNewUserForm, UserProfileForm, AgencyNetworkForm, AgencyOrganigrammForm, UserTimeForm, AgencyTimeManagement
from .forms import UsersSelfChangeForm, UsersNotificationForm, AgencyGroupPerms, AgencyModulsForm, UserNewUserForm, UserProfileForm, AgencyNetworkForm, AgencyOrganigrammForm, UserTimeForm, AgencyTimeManagement, AbsenceReasonForm
from django.contrib import messages
from django.contrib.auth import update_session_auth_hash
from django.contrib.auth.forms import PasswordChangeForm
@ -19,12 +19,18 @@ from users.models import Profile
from areas.models import Areas
from tasks.models import Tasks
import webcolors
from datetime import datetime
import datetime
from datetime import date
from standards.models import Standards
from timemanagement.models import AbsenceReason
from timemanagement.models import AbsenceReason, FreeDays
from django.core.mail import send_mail
from django.conf import settings
import re
import re, os, csv, requests
from django.templatetags.static import static
from django.db.models import DateField
from django.views.generic import DeleteView, UpdateView
from timemanagement.forms import AddFreeDayForm
from django.urls import reverse_lazy
def randomString(stringLength=10):
"""Generate a random string of fixed length """
@ -177,22 +183,138 @@ def SettingsAgency(request, context):
context['agencyform'] = AgencyUpdateForm(instance=request.user.profile.agency)
return render(request, 'dasettings/settings.html', context)
from django.db.models import F, Func, Value
@login_required
def FreeDaysManagemenet(request, initload=0):
if(initload==1):
context = {
'active_link' : 'dasettings',
'init_freedays' : True
}
return render(request, 'dasettings/freedays_management.html', context)
else:
context = {
'active_link' : 'dasettings',
'freedays' : FreeDays.objects.filter(agency=request.user.profile.agency).order_by("-day")
}
return render(request, 'dasettings/freedays_management.html', context)
@login_required
def FreeDayAdd(request):
if request.POST:
freedayform = AddFreeDayForm(request.POST, instance=request.user.profile.agency)
if freedayform.is_valid():
fd = FreeDays(agency=request.user.profile.agency, day=freedayform.cleaned_data['day'], year=freedayform.cleaned_data['day'].year, name=freedayform.cleaned_data['name']).save()
messages.success(request, f'Freier Tag hinzugefügt')
context = {
"active_link" : "dasettings",
}
return redirect("tm-managemenetfreedays")
else:
messages.success(request, f'Fehler beim hinzufügen!')
return redirect("tm-managemenetfreedays")
else:
context = {
"active_link" : "dasettings",
"form" : AddFreeDayForm()
}
return render(request, 'dasettings/freedays_add.html', context)
class FreeDayDeleteView(LoginRequiredMixin, DeleteView):
model = FreeDays
success_url = reverse_lazy('tm-managemenetfreedays')
template_name = 'dasettings/freedays_confirm_delete.html'
def delete(self, request, *args, **kwargs):
response = super(FreeDayDeleteView, self).delete(request, *args, **kwargs)
messages.success(request, f'Freier Tag wurde gelöscht!')
return response
def get_context_data(self, **kwargs):
context = super(FreeDayDeleteView, self).get_context_data(**kwargs)
context['active_link'] = 'dasettings'
return context
class AbsenceReasonDeleteView(LoginRequiredMixin, DeleteView):
model = AbsenceReason
success_url = reverse_lazy('dasettings')
template_name = 'dasettings/absencereason_confirm_delete.html'
def delete(self, request, *args, **kwargs):
response = super(AbsenceReasonDeleteView, self).delete(request, *args, **kwargs)
messages.success(request, f'Abwesenheitskategorie wurde gelöscht!')
return response
def get_context_data(self, **kwargs):
context = super(AbsenceReasonDeleteView, self).get_context_data(**kwargs)
context['active_link'] = 'dasettings'
return context
class AbsenceReasonAddView(LoginRequiredMixin, CreateView):
model = AbsenceReason
success_url = reverse_lazy('dasettings')
form_class = AbsenceReasonForm
template_name = 'dasettings/absencereason_add.html'
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
context.update({'active_link' : 'dasettings'})
return context
def form_valid(self, form):
# Send message to the site
messages.success(self.request, f'Abwesenheitskategorie angelegt!')
# SAVE OBJECTS TO SIGNALE!
form.instance.agency = self.request.user.profile.agency
return super().form_valid(form)
class AbsenceReasonUpdateView(LoginRequiredMixin, UpdateView):
model = AbsenceReason
template_name = 'dasettings/absencereason_update.html'
success_url = reverse_lazy('dasettings')
form_class = AbsenceReasonForm
def form_valid(self, form):
# Send message to the site
messages.success(self.request, f'Abwesenheitskategorie aktualisiert!')
return super().form_valid(form)
def get_context_data(self, **kwargs):
context = super(AbsenceReasonUpdateView, self).get_context_data(**kwargs)
context['active_link'] = 'dasettings'
return context
@login_required
def SettingsAgencyModuls(request, context):
if request.POST.get("form_type") == "agencymodform":
agencymoduleform = AgencyModulsForm(request.POST, instance=request.user.profile.agency)
if agencymoduleform.is_valid():
agencymoduleform.save()
agencymoduleform.save()
# Check, if Timemanagement is deactivate, to deactivate Zeiterfassung
if(request.user.profile.agency.module_timemanagement == False):
ag = request.user.profile.agency
ag.module_timemanagement_ze = False
if(request.user.has_perm("users.modulesconfig")):
FreeDays.objects.filter(agency=request.user.profile.agency).delete()
ag.save()
context['modulform'] = AgencyModulsForm(instance=request.user.profile.agency)
messages.success(request, f'Moduleinstellungen aktualisiert!')
return render(request, 'dasettings/settings.html', context)
temp_freedays = FreeDays.objects.filter(agency=request.user.profile.agency)
if(request.user.profile.agency.module_timemanagement and len(temp_freedays) == 0):
messages.success(request, f'Moduleinstellungen aktualisiert! Bitte prüfen Sie Ihre Feiertagseinstellungen')
return redirect('tm-initload', 1)
else:
context['modulform'] = AgencyModulsForm(instance=request.user.profile.agency)
messages.success(request, f'Moduleinstellungen aktualisiert!')
return render(request, 'dasettings/settings.html', context)
else:
context['modulform'] = AgencyModulsForm(instance=request.user.profile.agency)
messages.success(request, f'Fehler beim aktualisieren! Bitte wenden Sie sich an den Support.')
@ -517,11 +639,64 @@ def SettingsAjaxRouter(request):
else:
data = {"userfullname" : tempuser.first_name + " " + tempuser.last_name}
success = False
elif request.method == 'GET' and request.GET['action'] == "initloadfreedays" :
if(request.user.has_perm('users.modulesconfig')):
temp_freedays = FreeDays.objects.filter(agency=request.user.profile.agency)
if(len(temp_freedays) == 0):
tempdays_thisyear = loadingFreeDays(request.user.profile.agency.plz, date.today().year)
tempdays_lastyear = loadingFreeDays(request.user.profile.agency.plz, date.today().year - 1)
tempdays_nextyear = loadingFreeDays(request.user.profile.agency.plz, date.today().year + 1)
if(tempdays_thisyear != False):
for k in tempdays_lastyear.keys():
tempdate = tempdays_lastyear[k]["datum"].split("-")
FreeDays(agency=request.user.profile.agency, name=k, day=datetime.datetime(int(tempdate[0]),int(tempdate[1]),int(tempdate[2])), year=date.today().year-1).save()
for k in tempdays_thisyear.keys():
tempdate = tempdays_thisyear[k]["datum"].split("-")
FreeDays(agency=request.user.profile.agency, name=k, day=datetime.datetime(int(tempdate[0]),int(tempdate[1]),int(tempdate[2])), year=date.today().year).save()
for k in tempdays_nextyear.keys():
tempdate = tempdays_nextyear[k]["datum"].split("-")
FreeDays(agency=request.user.profile.agency, name=k, day=datetime.datetime(int(tempdate[0]),int(tempdate[1]),int(tempdate[2])), year=date.today().year+1).save()
messages.success(request, f'Feiertage erfolgreich gespeichert!')
success = True
else:
success = False
else:
data = {"userfullname" : tempuser.first_name + " " + tempuser.last_name}
success = False
else:
success = False
return JsonResponse({"success" : success, "data" : data})
def loadingFreeDays(plz, year):
# 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 str(row[1]) == str(plz):
land = row[6]
break;
if(land != False):
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
'''
UserProfileUpdate
@ -577,6 +752,7 @@ def UserProfileUpdate(request, pk, newuser=0):
elif(request.POST["form_type"] == "contract"):
formtosave = UserTimeForm(request.POST, instance=UserTime.objects.get(user=usertochange))
if(formtosave.is_valid()):
messages.success(request, f'Vertragsdaten gespeichert!')
formtosave.save()
@ -865,7 +1041,6 @@ def DelAgInv(request, pk):
@login_required
def DelFromAgn(request, agn, ag):
return redirect('managagn', agn)
@login_required

View File

@ -15,6 +15,7 @@ from datetime import datetime, timedelta
BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
############################################## DEV #####################################
BASE_URL = "https://dev01.digitale-agentur.com/"
CRONAPIKEY = "gCddsaz6NOnE9QbXZM5LasdEk122D"

View File

@ -37,8 +37,7 @@
<small>
<i class="fas fa-pen"></i>
</small></a>
{% endif %}
</div>
{% endif %}
</td>
{% endif %}
</tr>

View File

@ -14,9 +14,8 @@
<div class="col-12">
<ul class="nav nav-tabs" id="area_tabs" role="tablist" >
{% for area in areas %}
<li class="nav-item " >
<!--<a class="nav-link " id="{{area.id}}" style="opacity:0.8;background-color: {{area.color}}; color: #FFFFFF" data-toggle="tab" href="#t_{{area.id}}" role="tab" aria-controls="t_{{area.id}}" aria-selected="false">{{area.name}}</a>-->
<a class="nav-link " id="{{area.id}}" style="" data-toggle="tab" href="#t_{{area.id}}" role="tab" aria-controls="t_{{area.id}}" aria-selected="false">{{area.name}}</a>
<li class="nav-item " >
<a class="nav-link " id="{{area.id}}" style="border-bottom: 3px solid {{area.color}}; margin-bottom: -4px;" data-toggle="tab" href="#t_{{area.id}}" role="tab" aria-controls="t_{{area.id}}" aria-selected="false">{{area.name}}</a>
</li>
{% endfor %}
{% if agencynetworks|length > 0 %}
@ -26,7 +25,7 @@
{% endif %}
<li class="nav-item {% if agencynetworks|length == 0 %}ml-auto{% endif %}">
<a class="nav-link" id="userown" data-toggle="tab" href="#t_userown" role="tab" aria-controls="t_userown" aria-selected="false">Eigene Standards</a>
<a class="nav-link" id="userown" data-toggle="tab" href="#t_userown" role="tab" aria-controls="t_userown" aria-selected="false">Eigene Standards</a>
</li>
{% if perms.users.standardmanager %}
<li class="nav-item" style="float: left">

View File

@ -454,4 +454,23 @@ def getonlinestatuscolor(user):
elif(user.profile.onlinestatus == 3):
maincolor = "grey"
return maincolor
return maincolor
tempday = False
@register.simple_tag
def setMessageDayInfo(info):
global tempday
tempday = info.sendtime.day
return ""
@register.simple_tag
def getMessageDayInfo(info):
global tempday
if info.sendtime.day > tempday:
tempday = info.sendtime.day
return True
else:
return False

View File

@ -1,7 +1,7 @@
from bootstrap_datepicker_plus import DatePickerInput
from django import forms
from django.forms import ModelForm
from .models import Absence, AbsenceReason
from .models import Absence, AbsenceReason, FreeDays
from users.models import UserFullName
class AddAbsence(forms.ModelForm):
@ -62,4 +62,26 @@ class ConfirmAbsenceForm(forms.ModelForm):
def __init__(self, *arg, **kwargs):
super(ConfirmAbsenceForm, self).__init__(*arg, **kwargs)
self.fields['confirm_info'].widget.attrs['rows'] = 3
self.fields['confirm_info'].widget.attrs['rows'] = 3
# NEW USER FORM
class AddFreeDayForm(forms.ModelForm):
class Meta:
model = FreeDays
labels = {
"day" : "Datum",
"name" : "Bezeichnung"
}
fields = [
"name", "day"
]
widgets = {
'day': DatePickerInput(options={"format":'DD.MM.YYYY', "locale":'de'}),
}
def __init__(self, *arg, **kwargs):
super(AddFreeDayForm, self).__init__(*arg, **kwargs)
self.fields['name'].required = True
self.fields['day'].required = True

View File

@ -2,6 +2,7 @@ from django.db import models
from django.contrib.auth.models import User
from users.models import Agency
from django.core.exceptions import ValidationError
from colorful.fields import RGBColorField
# Create your models here.
class Workday(models.Model):
@ -23,7 +24,8 @@ class AbsenceReason(models.Model):
name = models.CharField(default="", max_length=200)
need_confirm = models.BooleanField(default=True)
need_rep = models.BooleanField(default=True)
is_holiday = models.BooleanField(default=True)
is_holiday = models.BooleanField(default=True)
color = RGBColorField(colors=['#FFB900', '#E74856', '#0078D7', '#0099BC', '#7A7574'], default='#0099BC', blank=True)
def __str__(self):
return f'{self.name}'
@ -31,8 +33,8 @@ class AbsenceReason(models.Model):
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 = models.DateField(default=None, null=True, blank=True)
end = models.DateField(default=None, null=True, blank=True)
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)
@ -53,7 +55,7 @@ class Absence(models.Model):
class FreeDays(models.Model):
agency = models.ForeignKey(Agency, on_delete=models.CASCADE)
day = models.DateTimeField(default=None, null=True, blank=True)
day = models.DateField(default=None, null=True, blank=True)
name = models.CharField(default="", max_length=200)
year = models.IntegerField(default=0)

View File

@ -13,8 +13,8 @@ Informationen: {{absence.info}}<br />
{{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>
<button type="button" class="btn btn-primary" onclick="javascript:noconfirmAbsence({{absence.pk}})">Ablehnen</button>
<button type="button" class="btn" onclick="javascript:confirmAbsence({{absence.pk}})">Annehmen</button>
</div>
</form>
<script type="text/javascript">

View File

@ -30,7 +30,7 @@
{% if isfree %}
<!-- FREEDAYS -->
<td id="{{actfcounter}}_{{forloop.counter}}_{{us.pk}}_free" style="background-color: #e74a3b" data-toggle="tooltip" data-placement="top" title="{{isfreename}}">
<td id="{{actfcounter}}_{{forloop.counter}}_{{us.pk}}_free" style="background-color: #9C9C9C" data-toggle="tooltip" data-placement="top" title="{{isfreename}}">
{% elif da.weekday == 5 or da.weekday == 6 %}
<!-- WEEKEND -->
<td id="{{actfcounter}}_{{forloop.counter}}_{{us.pk}}_free" style="background-color: #d3d3d3">
@ -46,9 +46,9 @@
class="partialfilling"
style="background-size: 50% 100%"
{% else %}
style="background-color: #36b9cc"
style="background-color: {{abday.reason.color}}"
{% 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 %} ">
data-toggle="tooltip" data-placement="top" title="{{abday.reason.name}} {% if abday.representator != None %} | Vertreter {{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 %}
@ -58,8 +58,8 @@
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 %} ">
style="background-color: {{abday.reason.color}}"
{% endif %} data-toggle="tooltip" data-placement="top" title="Abwesend {% if abday.representator != None %} | Vertreter {{abday.representator.first_name}} {{abday.representator.last_name}} {% endif %} ">
{% endif %}
{% elif abday.confirm_status == 1 %}
{% if user|usergperm:"absencemanager" %}
@ -145,12 +145,12 @@
{% getsomemonths as months %}
{% for m in months %}
<button class="btn
{% if forloop.counter == activemonth %} btn-secondary {% else %} btn-primary {% endif %}
{% if forloop.counter == activemonth %} btn-primary {% else %} btn-secondary {% 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>
<button type="button" class="btn btn-primary " data-dismiss="modal">Schließen</button>
</div>
</div>
</div>
@ -190,6 +190,7 @@ document.getElementById("id_reason").addEventListener("change", function(){
rid : reasonid
},
success : function(data){
//CHANGE REPRESENTOR
if(data["isreq"]){
$("#id_representator").prop('required',true);
$("label[for*='id_representator']").html("Vertreter*");
@ -198,6 +199,16 @@ document.getElementById("id_reason").addEventListener("change", function(){
$("#id_representator").prop('required',false);
$("label[for*='id_representator']").html("Vertreter");
}
//CHANGE HOLIDAYCOUNT
if(data["isholiday"] == false){
$("#noholidays_container").show();
$("#restholidays_container").hide();
}
else{
$("#noholidays_container").hide();
$("#restholidays_container").show();
recalculateChoosenDaysAfterInit();
}
}
});
})
@ -261,7 +272,6 @@ else{
user_has_right = false;
}
function recalculateChoosenDays(){
seldates = [];
userid = "";
@ -276,17 +286,84 @@ function recalculateChoosenDays(){
$("#div_id_end").show();
$("#div_id_end_ishalf").show();
$("#startAbsenceProgress").modal("toggle");
$("#id_start").data("DateTimePicker").date(date_start);
$("#id_end").data("DateTimePicker").date(date_end);
$("#id_start").data("DateTimePicker").date(date_start);
$("#id_end").data("DateTimePicker").date(date_end);
$.ajax({
type: "GET",
url: "{% url 'tm-ajax' %}",
data:{
action : "getrestholidays",
userid : userid,
startdate : date_start.getFullYear() + "__" + (date_start.getMonth()+1) + "__" + date_start.getDate(),
enddate : date_end.getFullYear() + "__" + (date_end.getMonth()+1) + "__" + date_end.getDate(),
start_half : $("#id_start_ishalf").prop("checked"),
end_half : $("#id_end_ishalf").prop("checked"),
},
success : function(data){
$("#restholidays").html(data["restholiday"])
$("#startAbsenceProgress").modal("show");
if(seldates.length == 1){
$("#div_id_end").hide();
$("#div_id_end_ishalf").hide();
}
if(seldates.length == 1){
$("#div_id_end").hide();
$("#div_id_end_ishalf").hide();
}
}
});
}
function recalculateChoosenDaysAfterInit(){
new_start = $("#id_start").datepicker().val();
new_end = $("#id_end").datepicker().val();
new_start = new_start.split(".");
new_end = new_end.split(".");
$.ajax({
type: "GET",
url: "{% url 'tm-ajax' %}",
data:{
action : "getrestholidays",
userid : userid,
startdate : new_start[2] + "__" + new_start[1] + "__" + new_start[0],
enddate : new_end[2] + "__" + new_end[1] + "__" + new_end[0],
start_half : $("#id_start_ishalf").prop("checked"),
end_half : $("#id_end_ishalf").prop("checked"),
},
success : function(data){
$("#restholidays").html(data["restholiday"])
//$("#startAbsenceProgress").modal("show");
if(seldates.length == 1){
$("#div_id_end").hide();
$("#div_id_end_ishalf").hide();
}
}
});
}
/*
CHANGE LISTENER
*/
$("#id_start").blur(function(){
recalculateChoosenDaysAfterInit();
})
$("#id_end").blur(function(){
recalculateChoosenDaysAfterInit();
})
$("#id_start_ishalf").change(function(){
recalculateChoosenDaysAfterInit();
})
$("#id_end_ishalf").change(function(){
recalculateChoosenDaysAfterInit();
})
$( function() {
$( "#timetable_team" ).selectable({
filter: 'td',

View File

@ -5,7 +5,6 @@
<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></h3>
<hr>
<div class="table-responsive ">
<table class="table table-hover" id="table_timemanagement" >
<thead>
@ -17,10 +16,8 @@
<th scope="col">Pausen</th>
<th scope="col">Gesamtzeit</th>
<th scope="col">Abwesenheit</th>
<th scope="col">Gleitzeit in h</th>
<th scope="col">Gleitzeit in h</th>
<th scope="col">&nbsp;</th>
</tr>
</thead>
<tbody id="table_contacts" >
@ -74,8 +71,8 @@
Möchten Sie wirklich den Arbeitstag am {{workday.start|date:"d.m"}} löschen?
</div>
<div class="modal-footer">
<button class="btn btn-danger" id="dodel_{{workday.pk}}" >Löschen</button>
<button type="button" class="btn btn-success" data-dismiss="modal">Abbrechen</button>
<button class="btn btn-primary" id="dodel_{{workday.pk}}" >Löschen</button>
<button type="button" class="btn" data-dismiss="modal">Abbrechen</button>
</div>
</div>

View File

@ -54,7 +54,6 @@
});
</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">
@ -66,8 +65,8 @@
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>
<button class="btn btn-primary" id="ab_{{ab.pk}}" >Löschen</button>
<button type="button" class="btn" data-dismiss="modal">Abbrechen</button>
</div>
</div>

View File

@ -70,9 +70,6 @@
<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">
@ -86,6 +83,31 @@
<div class="modal-body">
<h5>Abwesenheit für <b><span id="username_abscence"></span></b> beantragen</h5>
<hr>
<div id="restholidays_container">
<!--<h6>Verbleibender Urlaub <span id="holidayyear">:&nbsp;<span id="restholidays">Lade...</span></h6>
Drei Zahlen berechnet Resturlaub, Verbleibender aktuelles Jahr, Nächstes Jahr
Drei zahlen in Info-Icon, berechnet aus Resturlaub und aktuelles Jahr die Zahl zeigen!
Runterklappdinger für Jahresaufteilung
Beim ändern von Urlaubstagen
2020 2021 2022
30 32 30
Agentur: 30
Abwesenheiten - Meine Abwesenheiten, Übersicht über aktuelle Tage, Resturlaub in Jahren usw.
Bezug zu Urlaubsjahren mit Daten für Resturlaubsberechnung
-->
<h6>Resturlaub Urlaub 2019:&nbsp;<span id="restholidays">Lade...</span></h6>
</div>
<div id="noholidays_container" style="display: none;">
<h6>Abwesenheitsgrund ohne Urlaubsanspruch</h6>
</div>
<hr>
<form method="POST">
<input type="hidden" name="form_type" value="absenceform">
{% csrf_token %}
@ -94,7 +116,7 @@
</div>
<div class="modal-footer">
<button type="submit" class="btn btn-primary">Abwesenheit beantragen</button>
<button type="button" class="btn btn-secondary" data-dismiss="modal">Abbrechen</button>
<button type="button" class="btn btn" data-dismiss="modal">Abbrechen</button>
</div>
</form>
</div>
@ -135,7 +157,7 @@
</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>
<button type="button" class="btn btn" data-dismiss="modal">Abbrechen</button>
</div>
</div>
</div>
@ -362,4 +384,38 @@ $('#absencetabs a').on('click', function (e) {
{% else %}
<h3>Das Modul Abwesenheits- und Zeiterfassung wurde in ihrer Agentur deaktiviert.</h3>
{% endif %}
{% if missinguserdata|length > 0 %}
<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 Mitarbeiterinformationen</h5>
<button type="button" class="close" data-dismiss="modal" aria-label="Close">
<span aria-hidden="true">&times;</span>
</button>
</div>
<div class="modal-body">
<p>Zur Berechnung der Abwesenheiten und Urlaub müssen alle Mitarbeiter ein Einstellungsdatum haben. Dies fehlt bei folgenden Mitarbeitern:</p>
{% for m in missinguserdata %}
{{m.first_name}} {{m.last_name}}<br />
{% endfor %}
<br />
Bitte ergänzen Sie das Datum, da sonst keine Urlaubstage berechnet werden können.
</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");
})
</script>
{% endif %}
{% endblock content %}

View File

@ -14,7 +14,8 @@ 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):
@ -143,11 +144,20 @@ def AbsenceManagmenet(request, activemonth=False, activeyear=False):
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,
@ -294,12 +304,21 @@ def TimeAjax(request):
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,
@ -314,7 +333,8 @@ def TimeAjax(request):
if(reason.agency == request.user.profile.agency):
data = {
"success" : True,
"isreq" : reason.need_rep
"isreq" : reason.need_rep,
"isholiday" : reason.is_holiday
}
else:
data = {
@ -357,6 +377,67 @@ def TimeAjax(request):
"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
@ -365,3 +446,77 @@ def TimeAjax(request):
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)

View File

@ -268,7 +268,7 @@ class UserTime(models.Model):
holiday = models.FloatField(default=24.0)
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)
startdate = models.DateField(default=None, blank=True, null=True)
'''

View File

@ -25,38 +25,43 @@ from datetime import date
import channels.layers
from asgiref.sync import async_to_sync
def loadingFreeDays(plz):
def loadingFreeDays(plz, year):
# 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=';')
filecsv = csv.reader(csvfile, delimiter=';')
for row in filecsv:
if row[1] == plz:
if str(row[1]) == str(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)
r = requests.get(url = URL, params = PARAMS)
return r.json()
else:
return False
# CHECK SOMETHING WHEN USER LOGGED IN
@receiver(signal=user_logged_in, sender=User)
def checkForWorkDays(sender, user, request, **kwargs):
def checkForFreeDays(sender, user, request, **kwargs):
user.profile.onlinestatus = 0
user.save()
today = date.today()
if len(FreeDays.objects.filter(agency=user.profile.agency, year=today.year+2)) == 0:
tempdays = loadingFreeDays(user.profile.agency.plz, today.year+2)
if(tempdays != False):
for k in tempdays.keys():
tempdate = tempdays[k]["datum"].split("-")
FreeDays(agency=user.profile.agency, name=k, day=datetime.datetime(int(tempdate[0]),int(tempdate[1]),int(tempdate[2])), year=date.today().year+2).save()
'''
wd = Workday.objects.filter(user=user, end=None, start__day__lte=today.day)
for d in wd:
d.end = datetime.datetime(d.start.year, d.start.month, d.start.day, 23, 59, 00)
@ -65,7 +70,7 @@ def checkForWorkDays(sender, user, request, **kwargs):
if(b.end == None):
b.end = datetime.datetime(d.start.year, d.start.month, d.start.day, 23, 59, 00)
b.save()
'''
# CHECK SOMETHING WHEN USER LOGGED IN
@receiver(signal=user_logged_in, sender=User)
def checkDefaultAbsenceReasons(sender, user, request, **kwargs):
@ -87,25 +92,6 @@ def checkDefaultAbsenceReasons(sender, user, request, **kwargs):
@receiver(signal=user_logged_in, sender=User)
def checkAllFreeDaysLoaded(sender, user, request, **kwargs):
pass
'''
allFreeDays = FreeDays.objects.filter(agency=user.profile.agency, year=date.today().year)
# NO DAYS FOR THIS YEAR
if(len(allFreeDays) == 0):
tempdays = loadingFreeDays(user.profile.agency.plz)
for k in tempdays.keys():
tempdate = tempdays[k]["datum"].split("-")
FreeDays(agency=user.profile.agency, name=k, day=datetime.datetime(int(tempdate[0]),int(tempdate[1]),int(tempdate[2])), year=date.today().year).save()
'''
# Deletes all Notifications added to to delete news
@receiver(pre_delete, sender=News)
def del_news_notifications(sender, instance, **kwargs):

View File

@ -57,10 +57,9 @@
<!-- Page Wrapper -->
<div id="wrapper">
<!-- Sidebar -->
<ul class=" bg-gray-900 sidebar sidebar-dark accordion fixed-top" id="accordionSidebar">
<!-- Sidebar -->
<ul class=" bg-gray-900 sidebar sidebar-dark accordion fixed-top" id="accordionSidebar">
<!-- Sidebar - Brand -->
<a class="sidebar-brand d-flex align-items-center justify-content-center" href="{% url 'users-dashboard' %}">
<i class="fas fa-laptop"></i>
@ -229,7 +228,7 @@
</a>
</li>
<div style="" class="sidebar-heading">
<div style="" class="sidebar-heading ">
<!--<span style="float: left"><small>poweder by&nbsp;</small><img src="{% static 'users/img/VVE-Logo.png' %}" width="27%" class="mb-2"></span>-->
<img src="{% static 'users/img/VVE-Logo.png' %}" width="27%" class="mb-2">
<br />
@ -258,8 +257,14 @@
<div id="content-wrapper">
<!-- Main Content -->
<!-- Topbar -->
<div class="alert alert-info alert-dismissible" style="margin-bottom: -2px; text-align: center;"> <i class="fas fa-info-circle"></i>&nbsp;
Sie vertreten bis zum XXXX Darius Hannemann.
<button type="button" class="close" data-dismiss="alert">&times;</button>
</div>
<nav class="navbar navbar-expand navbar-light bg-white topbar mb-4 static-top shadow">
<!-- Sidebar Toggle (Topbar) -->
<button id="sidebarToggleTop" class="btn btn-link d-md-none rounded-circle mr-3" onclick="javascript:toggleSidebar()">
<i class="fa fa-bars"></i>
@ -464,9 +469,7 @@
<link href="{% static 'users/css/custom.css' %}" type="text/css" rel="stylesheet">
</body>
</html>