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, UserYearAbsenceInfo, UserTime from news.models import News from django.contrib.auth.models import Permission from notificsys.models import UserNotification from django.core.mail import send_mail from django.template.loader import render_to_string from tasks.models import Tasks from cloud.models import DataFile 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, user_logged_out from timemanagement.models import Workday, Breaks, AbsenceReason, FreeDays, Absence from datetime import date import datetime, json from django.utils import timezone import requests, csv, os from django.templatetags.static import static from django.conf import settings from datetime import date import channels.layers from asgiref.sync import async_to_sync from django.contrib.auth.decorators import login_required from datetime import timedelta 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].decode('utf-8')) == str(plz): land = row[6].decode('utf-8') 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 # CHECK SOMETHING WHEN USER LOGGED IN @receiver(signal=user_logged_out, sender=User) def checkForFreeDays(sender, user, request, **kwargs): user.profile.onlinestatus = 3 user.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", color="#0099BC", need_confirm=True, need_rep=True, is_holiday=True) new_ar_holidays.save() new_ar_specialholidays = AbsenceReason(agency=user.profile.agency, name="Sonderurlaub", need_confirm=True, need_rep=True, is_holiday=False, color="#F39C12") new_ar_specialholidays.save() new_ar_ill = AbsenceReason(agency=user.profile.agency, name="Krankheit", color="#E74C3C", need_confirm=False, need_rep=False, is_holiday=False) new_ar_ill.save() new_ar_school = AbsenceReason(agency=user.profile.agency, name="Berufsschule", color="#16A085", need_confirm=False, need_rep=False, is_holiday=False) new_ar_school.save() new_ar_education = AbsenceReason(agency=user.profile.agency, name="Fortbildung", color="#2ECC71", need_confirm=True, need_rep=True, is_holiday=False) new_ar_education.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 2 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 @receiver(pre_delete, sender=News) def del_news_notifications(sender, instance, **kwargs): UserNotification.objects.filter(elementid=instance.pk).delete() # SIGNALS FOR USER ''' @receiver(post_save, sender=User) def create_profile(sender, instance, created, **kwargs): print(instance) if created: Profile.objects.create(user=instance, agency=instance.agency, parent=instance.parent) #Wenn ein neuer Nutzer angelegt wird und dies der erste der Agentur ist, #erhält dieser automatisch alle verfügbaren Rechte! user_agency = User.objects.filter(profile__agency__pk=instance.agency.pk) if len(user_agency) == 1: tempuser = user_agency[0] temprof = Profile for ele in temprof._meta.permissions: tempperm = Permission.objects.get(codename=ele[0]) tempuser.user_permissions.add(tempperm) #tempuser.profile.func = 'lead' tempuser.save() ''' @receiver(post_save, sender=User) def save_profile(sender, instance, **kwargs): instance.profile.save() # SIGNALS FOR GROUPS @receiver(signal=m2m_changed, sender=User.groups.through) def adjust_group_notifications(instance, action, reverse, model, pk_set, using, *args, **kwargs): # IF FALSE NO MAILS WILL BE SEND - IN PRODUCTIVITY CHANGE TO TRUE # GLOBALSENDMAILS = True # GROUPSETTINGS FOR SOME USER WAS CHANGED if isinstance(instance, Group): group_touched = AgencyGroup.objects.get(group=instance) userid = list(pk_set)[0] user_touched = User.objects.get(pk=userid) # PUSH NOTIFICATION FOR GROUOPCHANGES if(user_touched.profile.add_new_group_push): if(action == 'post_remove'): newnotification = UserNotification(touser=user_touched, notificationtext="Sie wurden aus der Gruppe " + group_touched.agencygroupname + " entfernt.", notificationtype="groupchanges") newnotification.save() # A USER WAS ADDED TO A GROUP elif(action == 'post_add'): newnotification = UserNotification(touser=user_touched, notificationtext="Sie wurden zur Gruppe " + group_touched.agencygroupname + " hinzugefügt.", notificationtype="groupchanges") newnotification.save() # E-MAILNOTIFICATIONS FOR GROUPCHANGES if(user_touched.profile.add_new_group_mail): notificationtext = "" if(action == 'post_remove'): notificationtext = "Sie wurden aus der Gruppe " + group_touched.agencygroupname + " entfernt." username = user_touched.first_name + " " + user_touched.last_name msg_html = render_to_string('notificsys/notification_mail.html', {'username': username, 'notificationtext' : notificationtext}) if(GLOBALSENDMAILS): send_mail( 'Agentur-Benachrichtigung', 'Hallo ' + user_touched.first_name + ' ' + user_touched.last_name + '! ' + notificationtext, 'noreply@digitale-agentur.com', [user_touched.email], html_message=msg_html, fail_silently=True ) # A USER WAS ADDED TO A GROUP elif(action == 'post_add'): notificationtext = "Sie wurden zur Gruppe " + group_touched.agencygroupname + " hinzugefügt." username = user_touched.first_name + " " + user_touched.last_name msg_html = render_to_string('notificsys/notification_mail.html', {'username': username, 'notificationtext' : notificationtext}) if(GLOBALSENDMAILS): send_mail( 'Agentur-Benachrichtigung', 'Hallo ' + user_touched.first_name + ' ' + user_touched.last_name + '! ' + notificationtext, 'noreply@digitale-agentur.com', [user_touched.email], html_message=msg_html, fail_silently=True ) # SIGNAL FOR STANDARDS POST SAVE @receiver(post_save, sender=Standards) def save_standard(sender, instance, **kwargs): GLOBALSENDMAILS = True # NEW STANDARD AND DIRECT PUBLIC if(kwargs["created"]): usersofagency = User.objects.filter(profile__agency__pk=instance.agency.pk) targeturl = settings.BASE_URL + "standards/standard/" + str(instance.pk) + "/single" if(instance.public): for user in usersofagency: if(user.profile.agency_new_standard_mail): notificationtext = "Neuer Agenturstandard: " + instance.name username = user.first_name + " " + user.last_name msg_html = render_to_string('notificsys/notification_mail.html', {'username': username, 'notificationtext' : notificationtext, 'linktarget' : targeturl}) if(GLOBALSENDMAILS): send_mail( 'Agentur-Benachrichtigung', 'Hallo ' + user.first_name + ' ' + user.last_name + '! ' + notificationtext, 'noreply@digitale-agentur.com', [user.email], html_message=msg_html, fail_silently=True ) if(user.profile.agency_new_standard_push): newnotification = UserNotification(touser=user, notificationtext="Neuer Agenturstandard: " + instance.name, notificationtype="newstandard", elementid=instance.pk) newnotification.save() else: for user in usersofagency: if(user.has_perm("users.standardmanager")): newnotification = UserNotification(touser=user, notificationtext="Neuer unveröffentlichter Agenturstandard: " + instance.name, notificationtype="newstandard", elementid=instance.pk) newnotification.save() else: channel_layer = channels.layers.get_channel_layer() async_to_sync(channel_layer.group_send)("agency_" + str(instance.agency.pk), {'type' : 'update_standard'}) # SIGNAL FOR NEWS @receiver(post_save, sender=News) def save_news(sender, instance, **kwargs): GLOBALSENDMAILS = True if(kwargs["created"]): # Hier wird allen verbundenne Agenturmitgliedern die Info geschickt, dass es neue Agenturnews gibt channel_layer = channels.layers.get_channel_layer() async_to_sync(channel_layer.group_send)("agency_" + str(instance.agency.pk), {'type' : 'agency_newnews'}) usersofagency = User.objects.filter(profile__agency__pk=instance.agency.pk) targeturl = settings.BASE_URL + "news/news/" + str(instance.pk) + "/single" if(instance.go_online_on < timezone.now() and instance.agnotify): for user in usersofagency: if(user.profile.news_mail): notificationtext = "Neue Agenturnews: " + instance.name username = user.first_name + " " + user.last_name msg_html = render_to_string('notificsys/notification_mail.html', {'username': username, 'notificationtext' : notificationtext, 'linktarget' : targeturl}) if(GLOBALSENDMAILS): send_mail( 'Agentur-Benachrichtigung', 'Hallo ' + user.first_name + ' ' + user.last_name + '! ' + notificationtext, 'noreply@digitale-agentur.com', [user.email], html_message=msg_html, fail_silently=True ) if(user.profile.news_push): newnotification = UserNotification(touser=user, notificationtext="Neue Agenturnews: " + instance.name, notificationtype="agencynews", elementid=instance.pk) newnotification.save() else: instance.agnotify = False instance.save() else: channel_layer = channels.layers.get_channel_layer() async_to_sync(channel_layer.group_send)("agency_" + str(instance.agency.pk), {'type' : 'agency_newnews'}) # SIGNALS FOR TASK @receiver(signal=m2m_changed, sender=Tasks.usersfield.through) def adjust_group_notifications_task(instance, action, reverse, model, pk_set, using, *args, **kwargs): # IF FALSE NO MAILS WILL BE SEND - IN PRODUCTIVITY CHANGE TO TRUE # GLOBALSENDMAILS = True # A USER WAS TOUCHED ATT HIS TASKS user_touched = User.objects.get(pk=list(pk_set)[0]) taskname = instance.name # PUSH NOTIFICATION FOR GROUOPCHANGES if(user_touched.profile.add_task_push): if(action == 'post_remove'): newnotification = UserNotification(touser=user_touched, notificationtext="Sie wurden von der Tätigkeit " + taskname + " entfernt.", notificationtype="taskchange") newnotification.save() # A USER WAS ADDED TO A GROUP elif(action == 'post_add'): newnotification = UserNotification(touser=user_touched, notificationtext="Sie wurden der Tätigkeit " + taskname + " zugeordnet.", notificationtype="taskchange") newnotification.save() # E-MAILNOTIFICATIONS FOR GROUPCHANGES if(user_touched.profile.add_task_mail): notificationtext = "" if(action == 'post_remove'): notificationtext = "Sie wurden von der Tätigkeit " + taskname + " entfernt." username = user_touched.first_name + " " + user_touched.last_name msg_html = render_to_string('notificsys/notification_mail.html', {'username': username, 'notificationtext' : notificationtext}) if(GLOBALSENDMAILS): send_mail( 'Agentur-Benachrichtigung', 'Hallo ' + user_touched.first_name + ' ' + user_touched.last_name + '! ' + notificationtext, 'noreply@digitale-agentur.com', [user_touched.email], html_message=msg_html, fail_silently=True ) # A USER WAS ADDED TO A GROUP elif(action == 'post_add'): notificationtext = "Sie wurden der Tätigkeit " + taskname + " zugeordnet." username = user_touched.first_name + " " + user_touched.last_name msg_html = render_to_string('notificsys/notification_mail.html', {'username': username, 'notificationtext' : notificationtext}) if(GLOBALSENDMAILS): send_mail( 'Agentur-Benachrichtigung', 'Hallo ' + user_touched.first_name + ' ' + user_touched.last_name + '! ' + notificationtext, 'noreply@digitale-agentur.com', [user_touched.email], html_message=msg_html, fail_silently=True ) @receiver(signal=post_save, sender=AgencyNetworkPreperation) def save_agjoin_prep(sender, instance, **kwargs): newnotification = UserNotification(touser=instance.target_network.creator, notificationtext="Eine Agentur möchte Ihrem Verbund beitreten.", notificationtype="wantedag", elementid=instance.pk) newnotification.save() from django.core.signals import request_started from channels_presence.models import Room from channels_presence.models import Presence from channels_presence.signals import presence_changed # REQUEST MAIN STUFF @receiver(signal=request_started) def receiver_function(sender, **kwargs): # DELETES ALL PRESENCE-OBJETS LOWER THAN 15 MINUTES now_minus = datetime.datetime.now() - datetime.timedelta(minutes=2) Presence.objects.filter(last_seen__lt=now_minus).delete() # PREENCE CHANGED @receiver(signal=presence_changed) def update_presence_live(sender, **kwargs): channel_layer = channels.layers.get_channel_layer() async_to_sync(channel_layer.group_send)(str(kwargs["room"]), {'type' : 'update_presence_live'}) ''' ABWESENHEIT BERECHNUNG UND SPEICHERUNG DER NEUEN URLAUBSTAGE - VERWEIS AUF timemenagement.views ''' @receiver(signal=post_save, sender=Absence) def save_newabsence(sender, instance, **kwargs): post_save.disconnect(save_newabsence, sender=sender) if(instance.reason.is_holiday): newdata = getFinalHolidayData(instance) abinfo = list(UserYearAbsenceInfo.objects.filter(user=instance.user, year=instance.start.year))[0] abinfo_lastyear = "" abinfo_nextyear = "" is_lastyear = False abinfo_lastyear = list(UserYearAbsenceInfo.objects.filter(user=instance.user, year=instance.start.year-1)) if(len(abinfo_lastyear) > 0): is_lastyear = True abinfo_lastyear = abinfo_lastyear[0] is_nextyear = False abinfo_nextyear = list(UserYearAbsenceInfo.objects.filter(user=instance.user, year=instance.start.year+1)) if(len(abinfo_nextyear) > 0): is_nextyear = True abinfo_nextyear = abinfo_nextyear[0] multiple_info_needays = False if(hasattr(newdata[3], "__len__")): multiple_info_needays = True # Gleiches Jahr MIT Rest if(multiple_info_needays and newdata[3][2] == False): # Rest ist positiv, daher bleibt rest übrig, rest wird in absence gespeichert und vom rest des Jahres-Restes abgezogen # Rest ist positiv, damit bleibt Rest übrig if(newdata[3][0] > 0): instance.holidays_rest = abinfo.restdays - newdata[3][0] instance.save() abinfo.restdays = newdata[3][0] abinfo.save() # Rest ist negativ elif(newdata[3][0] < 0): instance.holidays_rest = (abinfo.restdays - newdata[3][0]) - newdata[3][0]*(-1) instance.holidays_normal = newdata[3][0]*(-1) instance.save() abinfo.restdays = 0 abinfo.days_inuse = abinfo.days_inuse + newdata[3][0]*(-1) abinfo.save() # Rest ist Urlaubsdauer else: instance.holidays_rest = abinfo.restdays instance.save() #abinfo.days_inuse = abinfo.days_inuse + abinfo.restdays abinfo.restdays = 0 abinfo.save() # Gleiches Jahr ohne Rest elif(not multiple_info_needays): abinfo.days_inuse = abinfo.days_inuse + newdata[3] abinfo.save() instance.holidays_normal = newdata[3] instance.save() # Mehrere Jahre elif(multiple_info_needays and newdata[3][2] == True): abinfo.days_inuse = abinfo.days_inuse + newdata[3][0] abinfo.save() abinfo_nextyear.days_inuse = abinfo_nextyear.days_inuse + newdata[3][1] abinfo_nextyear.save() # Hier werd der REST als vorjahreswert und NORMAL als nächstes Jahr gespeichert instance.holidays_normal = newdata[3][1] instance.holidays_rest = newdata[3][0] instance.save() else: print("Absence-Object is no holiday...") post_save.connect(save_newabsence, sender=sender) @receiver(signal=pre_delete, sender=Absence) def delete_absence(sender, instance, **kwargs): if(instance.reason.is_holiday): newdata = getFinalHolidayData(instance) abinfo = list(UserYearAbsenceInfo.objects.filter(user=instance.user, year=instance.start.year))[0] abinfo_lastyear = "" abinfo_nextyear = "" is_lastyear = False abinfo_lastyear = list(UserYearAbsenceInfo.objects.filter(user=instance.user, year=instance.start.year-1)) if(len(abinfo_lastyear) > 0): is_lastyear = True abinfo_lastyear = abinfo_lastyear[0] is_nextyear = False abinfo_nextyear = list(UserYearAbsenceInfo.objects.filter(user=instance.user, year=instance.start.year+1)) if(len(abinfo_nextyear) > 0): is_nextyear = True abinfo_nextyear = abinfo_nextyear[0] multiple_info_needays = False if(hasattr(newdata[3], "__len__")): multiple_info_needays = True print(newdata) if(instance.start.year != instance.end.year): abinfo.days_inuse = abinfo.days_inuse - instance.holidays_rest abinfo.save() abinfo_nextyear.days_inuse = abinfo_nextyear.days_inuse - instance.holidays_normal abinfo_nextyear.save() else: # Gleiches Jahr MIT Rest abinfo.days_inuse = abinfo.days_inuse - instance.holidays_normal abinfo.restdays = abinfo.restdays + instance.holidays_rest abinfo.save() else: print("Absence-Object is no holiday...") def getFinalHolidayData(abscence): user = abscence.user usertimedata = UserTime.objects.get(user=user) today = date.today() start_day_obj = abscence.start end_day_obj = abscence.end try: holidayloose_date = datetime.date(start_day_obj.year, int(usertimedata.loose_holidedate.split(".")[1]), int(usertimedata.loose_holidedate.split(".")[0])) except: holidayloose_date = datetime.date(2020, int(usertimedata.loose_holidedate.split(".")[1]), int(usertimedata.loose_holidedate.split(".")[0])) start_half = abscence.start_ishalf end_half = abscence.end_ishalf choosenyear = abscence.start.year yeardata = list(UserYearAbsenceInfo.objects.filter(user=user, agency=user.profile.agency, year=choosenyear))[0] holiday_thisyear = 0 holiday_lastyear = yeardata.restdays holiday_nextyear = 0 try: holiday_nextyear = list(UserYearAbsenceInfo.objects.filter(user=user, agency=user.profile.agency, year=choosenyear+1))[0].days - list(UserYearAbsenceInfo.objects.filter(user=user, agency=user.profile.agency, year=choosenyear+1))[0].days_inuse except: holiday_nextyear = yeardata.days # Urlaub innerhalb eines Jahres inkl. Prüfung auf Resturlaubsanspruch if(end_day_obj.year == start_day_obj.year): # Startt des Urlaubs NACH Verfallsdatum - nur aktuelles JAhr und die Zahl interessiert if(start_day_obj > holidayloose_date): need_days = (calculateHolidays(user, start_day_obj, end_day_obj, start_half, end_half))*(-1) holiday_thisyear = yeardata.days - yeardata.days_inuse - need_days else: need_days = (calculateHolidays(user, start_day_obj, end_day_obj, start_half, end_half))*(-1) # Kein Resturlaub if(yeardata.restdays == 0.0): holiday_thisyear = yeardata.days - yeardata.days_inuse - need_days # Resturlaub vorhanden, berechne mit Resturlaub else: holiday_lastyear = yeardata.restdays holiday_thisyear = yeardata.days - yeardata.days_inuse temp_holiday = holiday_lastyear - need_days if(temp_holiday < 0): holiday_lastyear = 0 holiday_thisyear = yeardata.days - yeardata.days_inuse + temp_holiday need_days = [temp_holiday, holiday_thisyear, False] else: holiday_lastyear = yeardata.restdays - need_days need_days = [temp_holiday, holiday_lastyear, False] # Urlaub geht über das nächstes Jahr hinweg else: holiday_lastyear = yeardata.restdays date_splitter = datetime.date(end_day_obj.year, 1, 1) #days_next_year = end_day_obj - date_splitter_postyear #days_this_year = date_splitter_preyear - start_day_obj need_days = [(calculateHolidays(user, start_day_obj, date_splitter, start_half, False))*(-1), (calculateHolidays(user, date_splitter, end_day_obj, False, end_half))*(-1), True] holiday_thisyear = yeardata.days - yeardata.days_inuse - (calculateHolidays(user, start_day_obj, date_splitter, start_half, False))*(-1) holiday_nextyear = holiday_nextyear - (calculateHolidays(user, date_splitter, end_day_obj, False, end_half))*(-1) data = [ holiday_thisyear, holiday_lastyear, holiday_nextyear, need_days ] return data def calculateHolidays(user, start, end, start_half, end_half): restdays = 0 allfreedays = FreeDays.objects.filter(agency=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 # Gibt die Woche als Wochentage zurück def daterange(date1, date2): for n in range(int ((date2 - date1).days)+1): yield date1 + timedelta(n)