Abwesenheit usw.

This commit is contained in:
Holger Trampe 2020-05-23 02:47:56 +02:00
parent 15348b2d25
commit 5e20c56368
25 changed files with 455 additions and 117 deletions

View File

@ -36,7 +36,7 @@
<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.sendtime|date:"H:m"}}</small></h6>
<h6 class="mt-3"><small>{{message.sendtime|date:"H:i"}}</small></h6>
<div style="text-align: left;" class="mt-1">
<span style="float: right !important; font-size: 1.0em;">
{{message.content}}
@ -48,7 +48,7 @@
<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>
<h6 class="mt-3"><small>{{message.author.first_name}} {{message.author.last_name}},&nbsp;{{message.sendtime|date:"H:i"}}</small></h6>
<div style="text-align: left;" class="mt-1">
<span style="float: left !important; font-size: 1.0em;">
{{message.content}}

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|date:"H:m"}}</small></h6>
<h6 class="mt-3"><small>{{newmessage.author.first_name}} {{newmessage.author.last_name}},&nbsp;{{newmessage.sendtime|date:"H:i"}}</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.sendtime|date:"H:m"}}</small></h6>
<h6 class="mt-3"><small>{{newmessage.sendtime|date:"H:i"}}</small></h6>
<div style="text-align: left;" class="mt-1">
<span style="float: right !important; font-size: 1.0em;">
{{newmessage.content}}

View File

@ -68,20 +68,16 @@ class UserTimeForm(forms.ModelForm):
class Meta:
model = UserTime
labels = {
"holiday" : "Urlaubstage",
"loose_holidedate" : "Urlaubstage aus Vorjahr verfallen am",
"loose_holidedate" : "Resturlaub verfällt am (XX.XX)",
"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", "holiday", "loose_holidedate", "holiday_start", ]
fields = ["startdate", "wd_mo", "wd_tu", "wd_we", "wd_th", "wd_fr", "loose_holidedate"]
widgets = {
'loose_holidedate': DatePickerInput(options={"format":'DD.MM.YYYY', "locale":'de'}),
"startdate" : DatePickerInput(options={"format":'DD.MM.YYYY', "locale":'de'})
}
@ -193,13 +189,16 @@ class UserProfileForm(forms.ModelForm):
class AbsenceReasonForm(forms.ModelForm):
rgb_color = forms.CharField(widget=forms.HiddenInput())
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"
"is_holiday" : "Geht vom Urlaub ab"
}
fields = ["name", "need_confirm", "need_rep", "is_holiday", "color"]
fields = ["name", "need_confirm", "need_rep", "is_holiday", "rgb_color"]

View File

@ -1,18 +1,59 @@
{% extends "users/base.html" %}
{% load crispy_forms_tags %}
{% load static %}
{% block content %}
{% if request.user.profile.agency.module_timemanagement %}
<script src="{% static 'users/js/colorPick.min.js' %}"></script>
<link rel="stylesheet" href="{% static 'users/css/colorPick.min.css' %}">
<style>
.colorPickSelector {
border-radius: 5px;
width: 36px;
height: 36px;
cursor: pointer;
-webkit-transition: all linear .2s;
-moz-transition: all linear .2s;
-ms-transition: all linear .2s;
-o-transition: all linear .2s;
transition: all linear .2s;
}
noclickeffect:active { border-style: outset !important;}
.colorPickSelector:hover { transform: scale(1.1); }
</style>
<div class="content-section col-6">
<h3>Abwesenheitskategorie anlegen</h3>
<hr>
<form method="POST" enctype="multipart/form-data">
{% csrf_token %}
{{ form|crispy }}
<div class="form-group">
<label for="abcolor_cal">Farbe im Teamkalender:</label>
<div id="abcolor_cal" class="colorPickSelector"></div>
</div>
<hr>
<button type="submit" class="btn btn-primary">Abwesenheitskategorie anlegen</button>&nbsp;
<a class="btn" href="{% url 'dasettings' %} ">Abbrechen</a>
</form>
</div>
<script type="text/javascript">
default_colorpickerinit = "#3498db";
abcolor_final= "#3498db";
$(".colorPickSelector").colorPick(
{
'initialColor': default_colorpickerinit,
'allowRecent': true,
'recentMax': 5,
'allowCustomColor': false,
'palette': ["#1abc9c", "#16a085", "#2ecc71", "#27ae60", "#3498db", "#2980b9", "#9b59b6", "#8e44ad", "#34495e", "#2c3e50", "#f1c40f", "#f39c12", "#e67e22", "#d35400", "#e74c3c", "#c0392b", "#ecf0f1", "#bdc3c7", "#95a5a6", "#7f8c8d"],
'onColorSelected': function() {
this.element.css({'backgroundColor': this.color, 'color': this.color});
abcolor_final = this.color;
$("#id_rgb_color").val(abcolor_final);
}
});
</script>
{% else %}
<h3>Das Modul Abwesenheitsplanung wurden in ihrer Agentur deaktiviert.</h3>
{% endif %}

View File

@ -1,20 +1,65 @@
{% extends "users/base.html" %}
{% load crispy_forms_tags %}
{% load static %}
{% block content %}
{% if request.user.profile.agency.module_timemanagement %}
<script src="{% static 'users/js/colorPick.min.js' %}"></script>
<link rel="stylesheet" href="{% static 'users/css/colorPick.min.css' %}">
<style>
.colorPickSelector {
border-radius: 5px;
width: 36px;
height: 36px;
cursor: pointer;
-webkit-transition: all linear .2s;
-moz-transition: all linear .2s;
-ms-transition: all linear .2s;
-o-transition: all linear .2s;
transition: all linear .2s;
}
noclickeffect:active { border-style: outset !important;}
.colorPickSelector:hover { transform: scale(1.1); }
</style>
<div class="content-section col-6">
<h3>Abwesenheitskategorie aktualisieren</h3>
<hr>
<form method="POST" enctype="multipart/form-data">
{% csrf_token %}
{{ form|crispy }}
{% csrf_token %}
{{ form|crispy }}
<div class="form-group">
<label for="abcolor_cal">Farbe im Teamkalender:</label>
<div id="abcolor_cal" class="colorPickSelector"></div>
</div>
<hr>
<button type="submit" class="btn btn-primary">Abwesenheitskategorie aktualisieren</button>&nbsp;
<a class="btn" href="{% url 'dasettings' %} ">Abbrechen</a>
</form>
</div>
<script type="text/javascript">
default_colorpickerinit = "{{object.color}}";
abcolor_final= "#3498db";
$(".colorPickSelector").colorPick(
{
'initialColor': default_colorpickerinit,
'allowRecent': true,
'recentMax': 5,
'allowCustomColor': false,
'palette': ["#1abc9c", "#16a085", "#2ecc71", "#27ae60", "#3498db", "#2980b9", "#9b59b6", "#8e44ad", "#34495e", "#2c3e50", "#f1c40f", "#f39c12", "#e67e22", "#d35400", "#e74c3c", "#c0392b", "#ecf0f1", "#bdc3c7", "#95a5a6", "#7f8c8d"],
'onColorSelected': function() {
this.element.css({'backgroundColor': this.color, 'color': this.color});
abcolor_final = this.color;
$("#id_rgb_color").val(abcolor_final);
}
});
</script>
{% else %}
<h3>Das Modul Abwesenheitsplanung wurden in ihrer Agentur deaktiviert.</h3>
{% endif %}
{% endblock content %}

View File

@ -2,15 +2,15 @@
{% 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>
</h4>
<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">Bestätigung</th>
<th scope="col">Vertretung</th>
<th scope="col">Urlaubstag</th>
<th scope="col">Farbe</th>
<th scope="col">&nbsp;</th>
</tr>
</thead>
@ -18,9 +18,10 @@
{% 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 ab.need_confirm %} <i class="fas fa-check"></i> {% else %} {% endif %}</td>
<td>{% if ab.need_rep %} <i class="fas fa-check"></i> {% else %} {% endif %}</td>
<td>{% if ab.is_holiday %} <i class="fas fa-check"></i> {% endif %}</td>
<td><i style="color: {{ab.color}}" class="fas fa-square-full"></i></td>
<td>
{% if user|usergperm:"moduleorganizer" %}
<a style="float: right" class="btn btn-secondary btn-sm ml-2" href="{% url 'abcat-delete' ab.pk %}">

View File

@ -34,7 +34,7 @@
{% for formfield in modulform %}
<div class="modal fade" id="modulesettings_{{formfield.name}}" tabindex="-1" role="dialog" data-backdrop="static" aria-labelledby="" aria-hidden="true">
<div class="modal-dialog modal-lg " role="document">
<div class="modal-dialog modal-lg " role="document" >
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title">Moduleinstellungen {{formfield.label_tag}}</h5>

View File

@ -94,11 +94,11 @@ noclickeffect:active { border-style: outset !important;}
</div>
<div class="modal-body">
<div class="form-group">
<label for="exampleInputPassword1">Bereichsname:</label>
<label for="newareaname">Bereichsname:</label>
<input class="form-control" id="newareaname" type="text" value="" placeholder="Bereichsname" onkeyup="javascript:validateAreaName(this.value)">
</div>
<div class="form-group">
<label for="exampleInputPassword1">Bereichsfarbe:</label>
<label for="areacolor">Bereichsfarbe:</label>
<div id="areacolor" class="colorPickSelector"></div>
</div>
<div id="newareaname_err" class="alert alert-danger mt-3" style="display: none">Falsche Eingabe! Keine Sonderzeichen!</div>
@ -732,7 +732,6 @@ function mainmodalAreaSave(){
}
//CHANGE AREA
else if(modalarea_action == 2){
console.log(newareacolor);
$.ajax(
{
type: "GET",

View File

@ -164,29 +164,58 @@
<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 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}}
{{usertime_form.holiday|as_crispy_field}}
{{usertime_form.holiday_start|as_crispy_field}}
{{usertime_form.loose_holidedate|as_crispy_field}}
{{usertime_form.startdate|as_crispy_field}}
<div class="col-12" >
<div class="col-4" style="margin-left: -10px;">
<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.startdate|as_crispy_field}}
{{usertime_form.loose_holidedate|as_crispy_field}}
</div>
<hr>
<p>Jahresübersicht&nbsp;<small><i data-toggle="tooltip" data-placement="top" title="Hier sehen Sie die aktuelle Jahresübersicht des Mitarbeiters. Beachten Sie das Format beim manuellen anpassen: XX,0 oder XX,5!" class="far fa-question-circle"></i></small>
<button type="button" id="changeHolidayData" style="float: right" class="btn btn-secondary btn-sm" onclick="javascript:loadUpdateTableHolidays()" data-toggle="tooltip" data-placement="top" title="Passen Sie die Urlaubstage und Resturlaubstage manuell an."><small><i class="fas fa-pen"></i></small></button>
<button type="button" id="changeHolidayDataSave" style="float: right; display: none" class="btn btn-primary btn-sm" onclick="javascript:saveUpdateTableHolidays()" data-toggle="tooltip" data-placement="top" title="Urlaub- und Resttage speichern."><small><i class="fas fa-check"></i></small></button>
</p>
<div id="year_overview">
<table class="table table-hover">
<thead>
<tr>
<th scope="col">Jahr</th>
{% for ab_info in user_years.all %}
<th scope="">{{ab_info.year}}</th>
{% endfor %}
</tr>
</thead>
<tbody>
<tr>
<th scope="row">Urlaub</th>
{% for ab_info in user_years.all %}
<td class="readytochange_holiday_rest" id="holiday_{{ab_info.pk}}">{{ab_info.days}}</td>
{% endfor %}
</tr>
<tr>
<th scope="row">Resturlaub</th>
{% for ab_info in user_years.all %}
<td class="readytochange_holiday_rest" id="rest_holiday_{{ab_info.pk}}">{{ab_info.restdays}}</td>
{% endfor %}
</tr>
</tbody>
</table>
</div>
</div>
<div class="col-12">
<hr>
@ -240,6 +269,55 @@
</div>
</div>
<script>
/*
DYNAMIC HOLIDAY CHANGES
*/
function loadUpdateTableHolidays(){
$.ajax(
{
type: "GET",
url: "{% url 'dasettings-ajax' %}",
data:{
action : "update_holidays",
userid: {{vieweduser}}
},
success: function( data )
{
$("#year_overview").html(data);
$("#changeHolidayDataSave").show();
$("#changeHolidayData").hide();
}
});
}
function saveUpdateTableHolidays(){
var new_data_arr = ""
new_data = $(".readytochange_holiday");
for(i = 0; i < new_data.length; i++){
tempele = new_data[i]["id"];
new_data_arr = new_data_arr + tempele + "__" + $("#" + tempele).val().replace(",", ".") + "___";
}
$.ajax(
{
type: "GET",
url: "{% url 'dasettings-ajax' %}",
data:{
action : "update_holidays_save",
new_data_info : new_data_arr,
userid: {{vieweduser}}
},
success: function( data )
{
$("#year_overview").html(data);
$("#changeHolidayDataSave").hide();
$("#changeHolidayData").show();
}
});
}
/*
DYNAMIC USERDATA CHANGES

View File

@ -6,7 +6,7 @@ from django.contrib import messages
from django.contrib.auth import update_session_auth_hash
from django.contrib.auth.forms import PasswordChangeForm
from users.usersforms import AgencyUpdateForm
from users.models import AgencyJob, AgencyGroup, AgencyNetwork, Agency, AgencyNetworkPreperation
from users.models import AgencyJob, AgencyGroup, AgencyNetwork, Agency, AgencyNetworkPreperation, UserYearAbsenceInfo
from django.contrib.auth.models import User, Group, Permission
from users.models import UserTime
import random
@ -31,7 +31,7 @@ from django.db.models import DateField
from django.views.generic import DeleteView, UpdateView
from timemanagement.forms import AddFreeDayForm
from django.urls import reverse_lazy
import re
def randomString(stringLength=10):
"""Generate a random string of fixed length """
letters = string.ascii_lowercase
@ -268,6 +268,7 @@ class AbsenceReasonAddView(LoginRequiredMixin, CreateView):
def form_valid(self, form):
# Send message to the site
messages.success(self.request, f'Abwesenheitskategorie angelegt!')
form.instance.color = form.cleaned_data["rgb_color"]
# SAVE OBJECTS TO SIGNALE!
form.instance.agency = self.request.user.profile.agency
return super().form_valid(form)
@ -279,8 +280,10 @@ class AbsenceReasonUpdateView(LoginRequiredMixin, UpdateView):
form_class = AbsenceReasonForm
def form_valid(self, form):
# Send message to the site
# Send message to the site
messages.success(self.request, f'Abwesenheitskategorie aktualisiert!')
self.object.color = form.cleaned_data["rgb_color"]
self.object.save()
return super().form_valid(form)
def get_context_data(self, **kwargs):
@ -668,6 +671,35 @@ def SettingsAjaxRouter(request):
else:
data = {"userfullname" : tempuser.first_name + " " + tempuser.last_name}
success = False
elif request.method == 'GET' and request.GET['action'] == "update_holidays" :
context = {
"user_years" : UserYearAbsenceInfo.objects.filter(user=User.objects.get(pk=request.GET["userid"])),
}
return render(request, 'dasettings/change_absence_yeardata.html', context)
elif request.method == 'GET' and request.GET['action'] == "update_holidays_save" :
# GET ELEMENTS
newHolidayData = request.GET["new_data_info"].split("___")
# EVERY ELEMENT GET ID AND SAVE NEW DAY-INFO
for ele in newHolidayData:
ele_elements = ele.split("__")
if(len(ele_elements) == 2):
ele_id = ele_elements[0].split("_")[3]
ele_type = ele_elements[0].split("_")[2]
temp_year = UserYearAbsenceInfo.objects.get(pk=ele_id, agency=request.user.profile.agency)
# TODO: Hier checken, warum das nicht so geil geht ;)
#if(re.match(r"^([1-9]{1}|0[0-9]{1}|1[0-9]{1}|2[0-9]{1}|3[0-9]{1}|4[0-9]{1}).([0]{1}|[5]{1})$", ele_elements[1])):
if(ele_type == "nor"):
temp_year.days = ele_elements[1]
elif(ele_type == "rest"):
temp_year.restdays = ele_elements[1]
temp_year.save()
context = {
"user_years" : UserYearAbsenceInfo.objects.filter(user=User.objects.get(pk=request.GET["userid"])),
}
return render(request, 'dasettings/data_absence_yeardata.html', context)
else:
success = False
return JsonResponse({"success" : success, "data" : data})
@ -740,6 +772,7 @@ def UserProfileUpdate(request, pk, newuser=0):
'first_name' : usertochange.first_name,
'last_name' : usertochange.last_name,
'usertime_form' : UserTimeForm(instance=UserTime.objects.get(user=usertochange)),
'user_years' : UserYearAbsenceInfo.objects.filter(user=usertochange),
'newuser' : newuser,
'vieweduser' : usertochange.pk,
'parentuser' : parentuser,
@ -752,11 +785,52 @@ 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()
return redirect('dasettings')
# CHECK IF HOLIDAYS_LOOSE IS CORRECT
if(not re.match(r"^([1-9]{1}|0[1-9]{1}|1[0-9]{1}|2[0-9]{1}|3[0-1]{1}).(1[0-2]|0[1-9]|[1-9])$", formtosave.cleaned_data["loose_holidedate"])):
messages.success(request, f'Fehlerhafte Eingabe!')
context = {
'active_link' : 'dasettings',
'user_fullname' : user_fullname,
'first_name' : usertochange.first_name,
'last_name' : usertochange.last_name,
'usertime_form' : UserTimeForm(instance=UserTime.objects.get(user=usertochange)),
'user_years' : UserYearAbsenceInfo.objects.filter(user=usertochange),
'newuser' : newuser,
'vieweduser' : usertochange.pk,
'parentuser' : parentuser,
'mail' : usertochange.email,
'imagelink' : usertochange.profile.get_photo_url,
'profileform' : UserProfileForm(instance=usertochange.profile),
'usertoparent' : User.objects.filter(profile__agency__pk=usertochange.profile.agency.pk, profile__visible=True)
}
return render(request, 'dasettings/user_usprof.html', context)
else:
# TRY TO CREATE DATE
date = formtosave.cleaned_data["loose_holidedate"].split(".")
try:
datetime.date(int(2020), int(date[1]), int(date[0]))
messages.success(request, f'Vertragsdaten gespeichert!')
formtosave.save()
return redirect('dasettings')
except:
messages.success(request, f'Fehlerhafte Eingabe! Das Verfallsdatum der Urlaubstage liegt außerhalb des Monats.')
context = {
'active_link' : 'dasettings',
'user_fullname' : user_fullname,
'first_name' : usertochange.first_name,
'last_name' : usertochange.last_name,
'usertime_form' : UserTimeForm(instance=UserTime.objects.get(user=usertochange)),
'user_years' : UserYearAbsenceInfo.objects.filter(user=usertochange),
'newuser' : newuser,
'vieweduser' : usertochange.pk,
'parentuser' : parentuser,
'mail' : usertochange.email,
'imagelink' : usertochange.profile.get_photo_url,
'profileform' : UserProfileForm(instance=usertochange.profile),
'usertoparent' : User.objects.filter(profile__agency__pk=usertochange.profile.agency.pk, profile__visible=True)
}
return render(request, 'dasettings/user_usprof.html', context)
else:
messages.success(request, f'Fehlerhafte Eingabe!')
context = {
@ -765,6 +839,7 @@ def UserProfileUpdate(request, pk, newuser=0):
'first_name' : usertochange.first_name,
'last_name' : usertochange.last_name,
'usertime_form' : UserTimeForm(instance=UserTime.objects.get(user=usertochange)),
'user_years' : UserYearAbsenceInfo.objects.filter(user=usertochange),
'newuser' : newuser,
'vieweduser' : usertochange.pk,
'parentuser' : parentuser,
@ -789,6 +864,7 @@ def UserProfileUpdate(request, pk, newuser=0):
'active_link' : 'dasettings',
'user_fullname' : user_fullname,
'usertime_form' : UserTimeForm(instance=UserTime.objects.get(user=usertochange)),
'user_years' : UserYearAbsenceInfo.objects.filter(user=usertochange),
'first_name' : usertochange.first_name,
'last_name' : usertochange.last_name,
'newuser' : newuser,

View File

@ -15,36 +15,37 @@ 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/"
############################################## LOCAL #####################################
BASE_URL = "http://localhost:8000/"
CRONAPIKEY = "gCddsaz6NOnE9QbXZM5LasdEk122D"
MAILINFOKEY = "jka7sd8iukashdna78skduJAHDsu6dilaksdjba65a68iadbhjak"
# SECURITY WARNING: don't run with debug turned on in production!
DEBUG = True
# MAIL DEV
EMAIL_HOST = 'smtp.strato.de'
EMAIL_PORT = 587
EMAIL_USE_TLS = True
EMAIL_HOST_USER = "support@dev01.digitale-agentur.com"
EMAIL_HOST_PASSWORD = "n2xd7emyKZFb6UREzvbintuUIG"
DEFAULT_FROM_EMAIL = "support@dev01.digitale-agentur.com"
# Database
# https://docs.djangoproject.com/en/2.2/ref/settings/#databases
# DEV
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.mysql',
'NAME' : 'digitaleagentur_dev01',
'USER' : 'digitaleagentur_dev01',
'PASSWORD' : 't3TvtGAOkFHYXdJlUMIu9u3U',
'NAME' : 'digitaleagentur',
'USER' : 'root',
'PASSWORD' : '',
'PORT' : 3306
}
}
# MAIL DEV
EMAIL_HOST = 'gymhum.de'
EMAIL_PORT = 587
EMAIL_USE_TLS = True
EMAIL_HOST_USER = "holger.trampe"
EMAIL_HOST_PASSWORD = "Motte2016_!"
DEFAULT_FROM_EMAIL = "holger.trampe@gymhum.de"
# REDIS
REDIS_URL = ("localhost", 6379)
############################################## DEV #####################################
################################################### LOCAL ###############################

View File

@ -9,7 +9,7 @@
<h3>Bereiche und Tätigkeiten von {{user_first_name}} {{user_last_name}}<span style="float: right">
{% if user|usergperm:"usermanager" %}
<button type="button" id="activatechangingorder" style="float: right" class="btn btn-secondary btn-sm" onclick="javascript:activateChangeTaskOrder()" data-toggle="tooltip" data-placement="top" title="Reihenfolge der Tätigkeiten anpassen"><small><i class="fas fa-pen"></i></small></button>
<button type="button" id="changingorder" style="float: right; display: none" class="btn btn-primary btn-sm" onclick="javascript:activateChangeTaskOrder()" data-toggle="tooltip" data-placement="top" title="Reihenfolge der Tätigkeiten anpassen"><small><i class="fas fa-check"></i></small></button>
<button type="button" id="changingorder" style="float: right; display: none" class="btn btn-primary btn-sm" onclick="javascript:activateChangeTaskOrder()" data-toggle="tooltip" data-placement="top" title="Reihenfolge der Tätigkeiten speichern."><small><i class="fas fa-check"></i></small></button>
<span style="float: right;">
{% if request.user.profile.agency.dynamicprofile %}

View File

@ -473,4 +473,28 @@ def getMessageDayInfo(info):
return True
else:
return False
@register.simple_tag
def getUserIsRep(user):
# REPRESENTATOR
today = date.today()
absence = Absence.objects.filter(agency=user.profile.agency, representator=user, start__lte=today, end__gte=today)
repstring = False
if(len(absence) > 0):
ab_counter = 0
repstring = "Sie vertreten "
for ab in absence:
repstring += ab.user.first_name + " " + ab.user.last_name + " bis zum " + ab.end.strftime("%d.%m.%Y") + "."
if(ab_counter + 1 < len(absence)):
repstring += " Sie vertreten zudem "
ab_counter += 1
# IN HOLIDAY?
absence_holiday = Absence.objects.filter(agency=user.profile.agency, user=user, start__lte=today, end__gte=today, reason__is_holiday=True)
if(len(absence_holiday) > 0):
repstring = "Wir wünschen Ihnen noch bis zum " + absence_holiday[0].end.strftime("%d.%m.%Y") + " einen schönen Urlaub!"
return repstring

View File

@ -42,7 +42,7 @@ class Absence(models.Model):
'''
CONFIRM_STATUS INFOS
0 = NO NEED TO CONFIRM AND CONFORM OK
0 = NO NEED TO CONFIRM AND CONFIRM OK
1 = IS CONFIRMED, AWAITING OK
2 = NOT CONFIRMED
@ -51,8 +51,6 @@ class Absence(models.Model):
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)
day = models.DateField(default=None, null=True, blank=True)

View File

@ -41,10 +41,12 @@
<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%"
style="background-size: 50% 100%;background-image: linear-gradient(to right, {{abday.reason.color}} 0%, {{abday.reason.color}} 17%, {{abday.reason.color}} 33%, {{abday.reason.color}} 67%, {{abday.reason.color}} 83%, {{abday.reason.color}} 100%); /* your gradient */
background-repeat: no-repeat; /* don't remove */"
{% elif abday.end_ishalf and abday.end.day == da.day %}
class="partialfilling"
style="background-size: 50% 100%"
style="background-size: 50% 100%; background-image: linear-gradient(to right, {{abday.reason.color}} 0%, {{abday.reason.color}} 17%, {{abday.reason.color}} 33%, {{abday.reason.color}} 67%, {{abday.reason.color}} 83%, {{abday.reason.color}} 100%); /* your gradient */
background-repeat: no-repeat; /* don't remove */"
{% else %}
style="background-color: {{abday.reason.color}}"
{% endif %}
@ -53,10 +55,12 @@
<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%"
style="background-size: 50% 100%; background-image: linear-gradient(to right, {{abday.reason.color}} 0%, {{abday.reason.color}} 17%, {{abday.reason.color}} 33%, {{abday.reason.color}} 67%, {{abday.reason.color}} 83%, {{abday.reason.color}} 100%); /* your gradient */
background-repeat: no-repeat; /* don't remove */"
{% elif abday.end_ishalf and abday.end.day == da.day %}
class="partialfilling"
style="background-size: 50% 100%"
class="partialfilling"
style="background-size: 50% 100%; background-image: linear-gradient(to right, {{abday.reason.color}} 0%, {{abday.reason.color}} 17%, {{abday.reason.color}} 33%, {{abday.reason.color}} 67%, {{abday.reason.color}} 83%, {{abday.reason.color}} 100%); /* your gradient */
background-repeat: no-repeat; /* don't remove */"
{% else %}
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 %} ">

View File

@ -1,5 +1,5 @@
from django.contrib import admin
from .models import Profile, Agency, AgencyGroup, AgencyJob, AgencyNetwork, AgencyNetworkPreperation, UserTime
from .models import Profile, Agency, AgencyGroup, AgencyJob, AgencyNetwork, AgencyNetworkPreperation, UserTime, UserYearAbsenceInfo
from .priomodel import Prio
from standards.models import StandardCommentRate, StandardComments
from django.contrib.auth.models import Permission
@ -27,3 +27,4 @@ admin.site.register(Breaks)
admin.site.register(AbsenceReason)
admin.site.register(Absence)
admin.site.register(FreeDays)
admin.site.register(UserYearAbsenceInfo)

View File

@ -265,12 +265,18 @@ class UserTime(models.Model):
wd_we = models.FloatField(default=8.0)
wd_th = models.FloatField(default=8.0)
wd_fr = models.FloatField(default=8.0)
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))
loose_holidedate = models.CharField(default="30.04", max_length=5)
startdate = models.DateField(default=None, blank=True, null=True)
class UserYearAbsenceInfo(models.Model):
agency = models.ForeignKey(Agency, on_delete=models.PROTECT, default=None)
user = models.ForeignKey(User, on_delete=models.CASCADE)
year = models.IntegerField()
days = models.FloatField(default=24.0)
restdays = models.FloatField(default=0.0)
'''
CLASS AgencyGroup

View File

@ -1,7 +1,7 @@
from django.db.models.signals import post_save, pre_delete, m2m_changed, pre_save
from django.contrib.auth.models import User, Group
from django.dispatch import receiver
from .models import Profile, Agency, AgencyGroup, AgencyNetworkPreperation
from .models import Profile, Agency, AgencyGroup, AgencyNetworkPreperation, UserYearAbsenceInfo
from news.models import News
from django.contrib.auth.models import Permission
from notificsys.models import UserNotification
@ -13,7 +13,7 @@ import os
from django.conf import settings
from django.utils import timezone
from standards.models import Standards
from django.contrib.auth.signals import user_logged_in
from django.contrib.auth.signals import user_logged_in, user_logged_out
from timemanagement.models import Workday, Breaks, AbsenceReason, FreeDays
from datetime import date
import datetime, json
@ -48,35 +48,17 @@ def loadingFreeDays(plz, year):
return False
# CHECK SOMETHING WHEN USER LOGGED IN
@receiver(signal=user_logged_in, sender=User)
@receiver(signal=user_logged_out, sender=User)
def checkForFreeDays(sender, user, request, **kwargs):
user.profile.onlinestatus = 0
user.save()
today = date.today()
user.profile.onlinestatus = 3
user.save()
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)
d.save()
for b in d.breaks.all():
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):
user.profile.onlinestatus = 0
user.save()
ar = AbsenceReason.objects.filter(agency=user.profile.agency)
if(len(ar) == 0):
new_ar_holidays = AbsenceReason(agency=user.profile.agency, name="Urlaub", need_confirm=True, need_rep=True, is_holiday=True)
new_ar_holidays.save()
@ -90,6 +72,53 @@ def checkDefaultAbsenceReasons(sender, user, request, **kwargs):
new_ar_school = AbsenceReason(agency=user.profile.agency, name="Berufsschule", need_confirm=False, need_rep=False, is_holiday=False)
new_ar_school.save()
today = date.today()
# FREEDAYS LADEN
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()
# CHECK FOR YEARS
# NO YEARS FOUND
if len(UserYearAbsenceInfo.objects.filter(agency=user.profile.agency)) == 0:
# CREATE DATA FOR EVERY USER
uina = User.objects.filter(profile__agency=user.profile.agency)
for u in uina:
UserYearAbsenceInfo(agency=user.profile.agency, user=u, year=today.year).save()
UserYearAbsenceInfo(agency=user.profile.agency, user=u, year=today.year+1).save()
UserYearAbsenceInfo(agency=user.profile.agency, user=u, year=today.year+2).save()
pass
# CREATE DATE FOR YEAR PLUS 3
elif len(UserYearAbsenceInfo.objects.filter(agency=user.profile.agency, year=today.year+2)) == 0:
uina = User.objects.filter(profile__agency=user.profile.agency)
for u in uina:
UserYearAbsenceInfo(agency=user.profile.agency, user=u, year=today.year+2).save()
'''
class UserYearAbsenceInfo(models.Model):
agency = models.ForeignKey(Agency, on_delete=models.PROTECT, default=None)
user = models.ForeignKey(User, on_delete=models.CASCADE)
year = models.IntegerField()
days = models.FloatField(default=24.0)
restdays = models.FloatField(default=0.0)
'''
'''
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)
d.save()
for b in d.breaks.all():
if(b.end == None):
b.end = datetime.datetime(d.start.year, d.start.month, d.start.day, 23, 59, 00)
b.save()
'''
# Deletes all Notifications added to to delete news

View File

@ -257,10 +257,28 @@
<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>
{% getUserIsRep request.user as repstring %}
{% if repstring != False %}
<div class="alert alert-info alert-dismissible" id="repholinfo" style="margin-bottom: -2px; text-align: center; display: none;"> <i class="fas fa-info-circle"></i>&nbsp;
{{repstring}}
<button type="button" class="close" data-dismiss="alert" onclick="javascript:closeRepHolInfo()">&times;</button>
</div>
<script type="text/javascript">
function closeRepHolInfo(){
localStorage.setItem("repholinfo_close", "1");
}
$(document).ready(function(){
showrepholinfo = localStorage.getItem("repholinfo_close");
if(showrepholinfo == null){
$("#repholinfo").show();
}
});
</script>
{% endif %}
<nav class="navbar navbar-expand navbar-light bg-white topbar mb-4 static-top shadow">
@ -338,19 +356,19 @@
</li>
<style type="text/css">
{% getonlinestatuscolor request.user as onlinecolor %}
.roundimg_base {
border-radius: 50%;
-webkit-box-shadow: 0px 0px 4px 5px {{onlinecolor}};
-moz-box-shadow: 0px 0px 4px 5px {{onlinecolor}};
box-shadow: 0px 0px 4px 5px {{onlinecolor}};
}
</style>
</style>
<div class="topbar-divider d-none d-sm-block"></div>
<!-- Nav Item - User Information -->
<li class="nav-item dropdown no-arrow">
<a class="nav-link dropdown-toggle" href="#" id="userDropdown" role="button" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
<span class="mr-2 d-none d-lg-inline text-gray-600 small">{{request.user.first_name}} {{request.user.last_name}}</span>
<span class="mr-2 d-none d-lg-inline text-gray-600 small">{{request.user.first_name}} {{request.user.last_name}}
</span>
<img id="userbaseprofilepicture" class="img-profile roundimg_base ml-2" src="{{ user.profile.get_photo_url }}">
</a>
<!-- Dropdown - User Information -->
@ -416,8 +434,10 @@
</div> <!-- End of Main Content CONTAINER FLUID-->
<!-- End of Content Wrapper -->
{% if active_link != 'chat' %}
<!--
<div id="chat_alluserscontent" style="position: fixed; bottom: 75px; right: 36px; z-index: 999;"></div>
<button id="chatButton" class="btn btn-primary" style="position: fixed; right: 36px; bottom: 30px;"><i class="far fa-comments"></i></button>
-->
{% endif %}
</div>
</div>

View File

@ -37,4 +37,9 @@
</div>
</div>
</div>
<script type="text/javascript">
$(document).ready(function(){
localStorage.clear();
})
</script>
{% endblock content %}

View File

@ -19,4 +19,9 @@
</p>
</div>
</div>
<script type="text/javascript">
$(document).ready(function(){
localStorage.clear();
})
</script>
{% endblock content %}

View File

@ -147,10 +147,15 @@ def toUpdate(request):
usersofagency = User.objects.filter(profile__agency=request.user.profile.agency)
for u in usersofagency:
# CREATE USERTIME-OBJECT
if(len(UserTime.objects.filter(user=u)) == 0):
usertime_new = UserTime(user=u)
usertime_new.save()
else:
ut = UserTime.objects.get(user=u)
if(ut.loose_holidedate == "2020-" or ut.loose_holidedate == "2021-"):
ut.loose_holidedate = "30.04"
ut.save()
'''
DASHBOARD-View
@ -833,7 +838,8 @@ def cronactions(request, code):
if(user.profile.news_push):
newnotification = UserNotification(touser=user, notificationtext="Neue Agenturnews: " + news.name, notificationtype="agencynews", elementid=news.pk)
newnotification.save()
data.update({"status" : "ok"})
data.update({"status" : "ok"})
elif(code == settings.MAILINFOKEY):
pass
'''