from django.views.generic import CreateView, ListView, UpdateView, DetailView, DeleteView, FormView, TemplateView from django.contrib import messages from django.shortcuts import render, redirect, reverse from django.urls import reverse_lazy from django.conf import settings from django.http import HttpResponseRedirect,HttpResponse, JsonResponse from .models import MainStatistic, MainSalesMonth from django.contrib.auth.models import User from chat.models import ChatMessage from users.models import Agency, AgencyBills, RegNotfallhilfe from standards.models import Standards import csv, os from auditlog.models import LogEntry import json from users.models import UserYearAbsenceInfo, UserTime from timemanagement.models import Workday, Absence, Breaks from recoverdir.models import * from .forms import AgencyBillForm, AdmWorkdayForm, AdmBreakAddForm from datetime import date, timedelta, datetime from organizer.models import QuickLinks, AGContacts, AGPassword from django.core.mail import EmailMessage from django.core.mail import EmailMultiAlternatives import io as BytesIO import base64 from django.http import HttpResponse from dateutil.relativedelta import * import requests from django.template.loader import render_to_string from cloud.models import DataFile import math import requests ''' Prüfung, ob angemeldeter User Mitarbeiterstatus hat. IMMER PER DISPATCH EINBAUEN! ''' def checkForStuffUser(request): if request.user.is_staff: return True else: return False ''' CSV mit Bestellungen herunterladen ''' def getCSVRDOrders(request): if(request.method == "GET"): response = HttpResponse(content_type='text/csv') today = date.today() response['Content-Disposition'] = 'attachment; charset=UTF-8; filename="DA-Export_NF_Bestellungen_' + str(today.day) + '_'+ str(today.month)+'_'+ str(today.year)+'.csv"' writer = csv.writer(response) writer.writerow(['Datum', 'E-Mail', 'Name', 'Personalnummer', 'mitgliedsnummer', 'PLZ', 'Stadt', 'Strasse', 'Rabatt']) orders = RegNotfallhilfe.objects.filter(wassend=False) for order in orders: rabatt = "NEIN" if order.rabatt: rabatt = "JA" writer.writerow([str(order.orderdate),str(order.mail),str(order.name),str(order.persnumber),str(order.mitgliedsnummer),str(order.plz), str(order.stadt),str(order.street), rabatt ]) order.wassend = True order.save() return response else: pass class delAgency(DeleteView): model = Agency success_url = reverse_lazy("adm-agencys") template_name = "adm/adm_admdelconfirm.html" def delete(self, *args, **kwargs): # Alle Abwesenheiten werden entfernt und dann erst die Agentur Absence.objects.filter(agency=self.get_object().pk).all().delete() messages.success(self.request, f'Agentur erfolgreich gelöscht!') return super(delAgency, self).delete(*args, **kwargs) def dispatch(self, *args, **kwargs): if(checkForStuffUser(self.request)): return super().dispatch(*args, **kwargs) else: messages.warning(self.request, f'Sie benötigen einen Mitarbeiter-Account, um diese Seiten aufzurufen!') return redirect("login") ''' Hauptansicht Statisik ''' class AdmMain(TemplateView): template_name = "adm/adm_main.html" def dispatch(self, *args, **kwargs): if(checkForStuffUser(self.request)): return super().dispatch(*args, **kwargs) else: messages.warning(self.request, f'Sie benötigen einen Mitarbeiter-Account, um diese Seiten aufzurufen!') return redirect("login") def get_context_data(self, **kwargs): context = super().get_context_data(**kwargs) context.update({'active_link' : "adm-statistic"}) context.update({'statistik' : MainStatistic.objects.all().order_by('staticdate') }) context.update({ "agencycount" : len(Agency.objects.all()), "usercount" : len(User.objects.all().exclude(is_staff=True, is_superuser=True)), "standardcount" : len(Standards.objects.all()), "chatmessagescount" : len(ChatMessage.objects.all()), "money" : MainSalesMonth.objects.all(), }) return context ''' Gesatmübersicht aller Rechnungen ''' class AdmBills(TemplateView): template_name = "adm/adm_bills.html" def dispatch(self, *args, **kwargs): if(checkForStuffUser(self.request)): return super().dispatch(*args, **kwargs) else: messages.warning(self.request, f'Sie benötigen einen Mitarbeiter-Account, um diese Seiten aufzurufen!') return redirect("login") def get_context_data(self, **kwargs): context = super().get_context_data(**kwargs) context.update({'active_link' : "adm-bills"}) context.update({'bills' : AgencyBills.objects.all().exclude(billstatus="voided")}) context.update({'bills_storno' : AgencyBills.objects.filter(billstatus="voided")}) return context ''' Erstellen einer neuen Rechnung ''' class AdmAddBill(CreateView): template_name = "adm/adm_addbill.html" model = AgencyBills success_url = reverse_lazy('adm-bills') form_class = AgencyBillForm def dispatch(self, *args, **kwargs): if(checkForStuffUser(self.request)): return super().dispatch(*args, **kwargs) else: messages.warning(self.request, f'Sie benötigen einen Mitarbeiter-Account, um diese Seiten aufzurufen!') return redirect("login") def form_valid(self, form): today = date.today() agency = form.cleaned_data['agency'] # USERCOUNT BERECHNEN usercount = len(User.objects.filter(profile__agency=agency)) if(usercount < 4): usercount = 0 else: usercount = usercount - 3 # HEADERS CURL headers = { 'Authorization': 'Bearer ' + settings.LEX_API, 'Content-Type': 'application/json', 'Accept': 'application/json', } plan = 1 start_date = form.cleaned_data["start"] start_date_string = start_date.strftime("%d.%m.%Y") end_date = start_date + relativedelta(months=1) end_date = end_date - relativedelta(days=1) end_date_string= end_date.strftime("%d.%m.%Y") # Rechnungsdatum passt ja voucher_date_today = date.today().strftime("%Y-%m-%d") monthword = "Monat" lexdata = { "voucherDate": voucher_date_today + "T00:00:00.000+00:00", "address" : { "name" : agency.name, "street": agency.street, "zip": agency.plz, "city": agency.city, "countryCode" : "DE" }, "totalPrice" : { "currency" : "EUR", }, "lineItems" : [ { "type" : "custom", "name" : "Digitale Agentur: Grundbetrag für " + str(plan) + " " + monthword, "quantity" : 1, "unitName" : "Stück", "description" : "Zeitraum " + start_date_string + " - " + end_date_string, "unitPrice" : { "currency" : "EUR", "netAmount" : 21.00, "taxRatePercentage" : 19 }, }, { "type" : "custom", "name" : "Digitale Agentur: Zusätzliche Nutzer", "description" : "Zeitraum " + start_date_string + " - " + end_date_string, "quantity" : usercount, "unitName" : "Stück", "unitPrice" : { "currency" : "EUR", "netAmount" : 3, "taxRatePercentage" : 19 }, } ], "taxConditions": { "taxType": "net" }, #"paymentConditions": { # "paymentTermLabel": "Bitte zahlen Sie innerhalb von 14 Tagen.", # "paymentTermDuration": 14, #}, "shippingConditions": { #"shippingDate": voucher_date_today + "T00:00:00.000+00:00", "shippingType": "none" } } json_data = json.dumps(lexdata) # WIEDER RAUSNEHMEN # NEUE RECHNUNG ALs ENTWURF #r = requests.post("https://api.lexoffice.io/v1/invoices/", data=json_data, headers=headers) # RICHTIGE RECHNUNG r = requests.post("https://api.lexoffice.io/v1/invoices/?finalize=true", data=json_data, headers=headers) if(r.status_code == 201): response_text = json.loads(r.text) newbill_id = response_text["id"] # OrganizationId berechnen, wenn noch nicht gesetzt r = requests.get("https://api.lexoffice.io/v1/invoices/" + response_text["id"], data=json_data, headers=headers) response_text = json.loads(r.text) form.instance.agency = agency form.instance.lexid = newbill_id form.instance.agency = agency form.instance.billtype="invoice" form.instance.billnumber = response_text["voucherNumber"] form.instance.billstatus = response_text["voucherStatus"] form.instance.start = start_date form.instance.end = end_date form.instance.plan = plan form.instance.usercount = usercount #newbill = AgencyBills(agency=agency, lexid=newbill_id, billtype="invoice", billnumber=response_text["voucherNumber"], billstatus=response_text["voucherStatus"], start=start_date, end=end_date, plan=plan, usercount=usercount) form.save() mail_to_send = "" if(agency.payment_address == None): mail_to_send = agency.agency_email else: mail_to_send = agency.payment_address # BCC Mail with Object - NICHT DEN IMPORT VERGESSEN!!! email = EmailMultiAlternatives( 'Digitale Agentur | Rechnung ' + str(response_text["voucherNumber"]), 'Sehr geehrte Nutzer, hiermit erhalten Sie eine neue Rechnung für die Digitale Agentur. Ihr Team der Digitalen Agentur', 'noreply@digitale-agentur.com', [mail_to_send], ['info@digitale-agentur.com'], headers={}, ) headers = { 'Authorization': 'Bearer ' + settings.LEX_API, 'Content-Type': 'application/json', 'Accept': 'application/json', } lexdata = { "renderType" : "pdf" } json_data = json.dumps(lexdata) r_final = requests.get("https://api.lexoffice.io/v1/invoices/"+newbill_id+"/document", data=json_data, headers=headers) json.loads(r_final.text) base64String = requests.get("https://api.lexoffice.io/v1/files/"+json.loads(r_final.text)["documentFileId"]+"/", data=json_data, headers=headers) content = base64.b64decode(base64String.text) msg_html = render_to_string('users/newbill_mail.html', {}) email.attach_alternative(msg_html, "text/html") email.attach('Rechnung_' + str(response_text["voucherNumber"]) + '.pdf', content, "application/pdf") email.send() return super(AdmAddBill, self).form_valid(form) def get_context_data(self, **kwargs): context = super().get_context_data(**kwargs) context.update({'active_link' : "adm-agencys"}) #context.update({'agencys' : Agency.objects.all()}) return context ''' Gesamtansicht der Agenturen ''' class AdmAgencys(TemplateView): template_name = "adm/adm_agencys.html" def dispatch(self, *args, **kwargs): if(checkForStuffUser(self.request)): return super().dispatch(*args, **kwargs) else: messages.warning(self.request, f'Sie benötigen einen Mitarbeiter-Account, um diese Seiten aufzurufen!') return redirect("login") def get_context_data(self, **kwargs): context = super().get_context_data(**kwargs) context.update({'active_link' : "adm-agencys"}) context.update({'agencys' : Agency.objects.all()}) return context class AdmUsers(TemplateView): template_name = "adm/adm_users.html" def dispatch(self, *args, **kwargs): if(checkForStuffUser(self.request)): return super().dispatch(*args, **kwargs) else: messages.warning(self.request, f'Sie benötigen einen Mitarbeiter-Account, um diese Seiten aufzurufen!') return redirect("login") def get_context_data(self, **kwargs): context = super().get_context_data(**kwargs) context.update({'active_link' : "adm-users"}) context.update({'users' : User.objects.all().exclude(is_staff=True, is_superuser=True)}) return context ''' Einzelansicht der Agenturen ''' class AdmAgencySingle(TemplateView): template_name = "adm/adm_agency_single.html" def dispatch(self, *args, **kwargs): if(checkForStuffUser(self.request)): return super().dispatch(*args, **kwargs) else: messages.warning(self.request, f'Sie benötigen einen Mitarbeiter-Account, um diese Seiten aufzurufen!') return redirect("login") def get_context_data(self, **kwargs): context = super().get_context_data(**kwargs) context.update({'active_link' : "adm-agencys"}) context.update({'agency' : Agency.objects.get(pk=kwargs['agpk'])}) context.update({'bills' : AgencyBills.objects.filter(agency=Agency.objects.get(pk=kwargs['agpk'])).order_by('-billdate')[:3]}) context.update({'users_of_agency' : User.objects.filter(profile__agency=Agency.objects.get(pk=kwargs['agpk'])).order_by('-last_name')}) return context class AdmUserSingle(TemplateView): template_name = "adm/adm_user_single.html" def dispatch(self, *args, **kwargs): if(checkForStuffUser(self.request)): return super().dispatch(*args, **kwargs) else: messages.warning(self.request, f'Sie benötigen einen Mitarbeiter-Account, um diese Seiten aufzurufen!') return redirect("login") def get_context_data(self, **kwargs): userrequested = User.objects.get(pk=kwargs['uspk']) context = super().get_context_data(**kwargs) context.update({'active_link' : "adm-users"}) context.update({'userdata' : userrequested}) # Loading Logindata logdata = LogEntry.objects.filter(object_pk=kwargs['uspk'])[:50] logdata_logins = [] for ele in reversed(logdata): try: datestring = json.loads(ele.changes)["last_login"][1] datestring = datestring.split(".")[0] logdata_logins.append(datetime.strptime(datestring, '%Y-%m-%d %H:%M:%S')) except: pass context.update({'logdata' : logdata_logins}) context.update({'workdays' : Workday.objects.filter(user=userrequested)}) context.update({'absences' : Absence.objects.filter(user=userrequested)}) context.update({'yearinfo' : UserYearAbsenceInfo.objects.filter(user=userrequested)}) context.update({'usertimedata' : UserTime.objects.get(user=userrequested)}) return context # CRONJOB, um die Statistik zu füllen! def statisticCronJob(request, code): data = {} if(code == settings.CRONAPIKEY_STATSTIC): print("STATISTIC is running...") today = date.today() ''' = models.FloatField(default=0.0) logins = models.IntegerField(default=0) ''' # AGENCYS agencycount = len(Agency.objects.all()) # USERS usercount = len(User.objects.all().exclude(is_staff=True, is_superuser=True)) # STANDARDS standardcount = len(Standards.objects.all()) # CHATMESSAGES chatmesscount = len(ChatMessage.objects.all()) # ABOCOUNT abocount = len(Agency.objects.filter(paymentplan=1)) # ABSENCE OBJECTS absenceobjects = len(Absence.objects.all()) # USER WITH TIMEMANAGEMENT user_active_timemanagement = len(User.objects.filter(usertime__usetime=True)) # ORGANIZEROBJECTS organizerobjects = len(QuickLinks.objects.all()) + len(AGContacts.objects.all()) + len(AGPassword.objects.all()) # AGENCY WITH RECOVERPASS agency_activerecover = 0 agency_activerecover_all = RecoverDirSetting.objects.all() for re in agency_activerecover_all: if len(re.logpass) > 0: agency_activerecover += 1 # FILES ''' TODO: Hier bitte einmal checken, ob umbenannte Dateien auch gefunden werden können oder nicht ''' allfiles = 0 try: files_data = DataFile.objects.all() allfiles = len(files_data) # FILE SOTRAGE allfiles_storage = 0.0 for f in files_data: allfiles_storage += os.stat(f.file.path).st_size except: pass # LOGINS YESTERDAY yesterday = today - timedelta(days=1) logins = 0 for u in User.objects.all(): try: logdata = list(LogEntry.objects.filter(object_pk=u.pk)[:1])[0] datestring = json.loads(logdata.changes)["last_login"][1] datestring = datestring.split(".")[0] logdate = datetime.strptime(datestring, '%Y-%m-%d %H:%M:%S') logdate = logdate.date() if logdate == yesterday: logins += 1 except: pass # RECOVEROBJECTS agency_recoverobjects = len(PersLetter.objects.all()) + len(Handlungsleitfaden.objects.all()) + len(RDContact.objects.all()) + len(RDTrustPerson.objects.all()) + len(Documents.objects.all()) + len(HandlungsleitfadenVF.objects.all()) + len(DepositVollmacht.objects.all()) + len(ErgoVerDir.objects.all()) + len(OnlineBank.objects.all()) + len(StreamingAbo.objects.all()) + len(DigitalAccounts.objects.all()) + len(Personal.objects.all()) + len(RDContract.objects.all()) + len(RDElse.objects.all()) # COUNT INVOICES WHEN FIRST DAY OF MONTH lastmonth = today - timedelta(days=today.day) monthvalue = 0.0 if today.day == 1: for bill in AgencyBills.objects.filter(billdate__month=lastmonth.month): newvalue = getLexOfficeBill(bill.lexid) if newvalue != False: monthvalue += newvalue nm = MainSalesMonth(value=monthvalue, salesmonthdate=lastmonth) nm.save() # Monatlicher MRR finalrma = 0 allag_withabo = Agency.objects.filter(paymentplan=1) abos = len(allag_withabo) * 21 extrausercount = 0 for ag in allag_withabo: user_ag = User.objects.filter(profile__agency=ag) if len(user_ag) > 3: extrausercount += len(user_ag) - 3 finalmrr = abos + 3*extrausercount newMainS = MainStatistic(agencys=agencycount,users=usercount,standards=standardcount,chatmessages=chatmesscount, active_abos=abocount, absenceobjects=absenceobjects, user_active_timemanagement=user_active_timemanagement, organizerobjects=organizerobjects, agency_recoverobjects=agency_recoverobjects, allfiles=allfiles, allfiles_storage=allfiles_storage, logins=logins, mrr=finalmrr) newMainS.save() data.update({"status" : "success"}) else: print("API STATISTIC CODE FAILED") data.update({"status" : "failed"}) return JsonResponse(data) # Return an Tax-Free Value of bill def getLexOfficeBill(billid): headers = { 'Authorization': 'Bearer ' + settings.LEX_API, 'Content-Type': 'application/json', 'Accept': 'application/json', } lexdata = { "renderType" : "pdf" } json_data = json.dumps(lexdata) returnvalue = False try: r_final = requests.get("https://api.lexoffice.io/v1/invoices/"+billid, data=json_data, headers=headers) billdata = json.loads(r_final.text) returnvalue = billdata['totalPrice']['totalNetAmount'] except: pass return returnvalue def convert_size(size_bytes): if size_bytes == 0: return "0B" size_name = ("B", "KB", "MB", "GB", "TB", "PB", "EB", "ZB", "YB") i = int(math.floor(math.log(size_bytes, 1024))) p = math.pow(1024, i) s = round(size_bytes / p, 2) return "%s %s" % (s, size_name[i]) ''' WORKDAY VIEWS Hier sind alle Views für Arbeitstage und Pausen (Create, Update, Delete) ''' class AdmWorkdayAdd(CreateView): model = Workday template_name = "adm/adm_workday_add.html" form_class = AdmWorkdayForm def form_valid(self, form): wd_user = User.objects.get(pk=self.kwargs['uspk']) wd = Workday(user=wd_user, agency=wd_user.profile.agency, start=form.cleaned_data['start'], end=form.cleaned_data['end'], target=form.cleaned_data["target"], freefield=form.cleaned_data["freefield"]) wd.save() return HttpResponseRedirect(self.get_success_url()) def get_context_data(self, **kwargs): context = super().get_context_data(**kwargs) context.update({'active_link' : 'adm-users'}) context.update({'user' : User.objects.get(pk=self.kwargs['uspk'])}) return context def get_success_url(self): return reverse('adm-user-single', kwargs={'uspk': self.kwargs['uspk']}) class AdmWorkdayUpdate(UpdateView): model = Workday form_class = AdmWorkdayForm template_name = "adm/adm_workday_update.html" def get_context_data(self, **kwargs): context = super().get_context_data(**kwargs) context.update({'active_link' : 'adm-users'}) return context def get_success_url(self): return reverse('adm-user-single', kwargs={'uspk': self.get_object().user.pk}) class AdmWorkdayDelete(DeleteView): model = Workday template_name = "adm/adm_workday_delete.html" def get_success_url(self): return reverse('adm-user-single', kwargs={'uspk': self.get_object().user.pk}) def get_context_data(self, **kwargs): context = super().get_context_data(**kwargs) context.update({'active_link' : 'adm-users'}) return context class AdmBreakDelete(DeleteView): model = Breaks template_name = "adm/adm_break_delete.html" def get_success_url(self): return reverse('adm-workday-update', kwargs={'pk': self.get_object().workday.pk}) def get_context_data(self, **kwargs): context = super().get_context_data(**kwargs) context.update({'active_link' : 'adm-users'}) return context class AdmAddBreak(CreateView): model = Breaks template_name = "adm/adm_break_add.html" form_class = AdmBreakAddForm def form_valid(self, form): wd = Workday.objects.get(pk=self.kwargs['pk']) b = Breaks(user=wd.user, agency=wd.user.profile.agency, workday=wd, start=form.cleaned_data["start"], end=form.cleaned_data["end"]) b.save() wd.breaks.add(b) wd.save() return HttpResponseRedirect(self.get_success_url()) def get_context_data(self, **kwargs): context = super().get_context_data(**kwargs) context.update({'active_link' : 'adm-users'}) context.update({'workday' : Workday.objects.get(pk=self.kwargs['pk'])}) return context def get_success_url(self): return reverse('adm-workday-update', kwargs={'pk': self.kwargs['pk']}) ''' IMPORT AGENCY ''' class AdmImport(TemplateView): template_name="adm/adm_import_overview.html" def get_context_data(self, **kwargs): context = super().get_context_data(**kwargs) context.update({'active_link' : 'adm-import'}) context.update({'agencys' : Agency.objects.all()}) return context from django.contrib.auth.models import Group from cloud.models import * class AdmImportFlow(TemplateView): template_name="adm/adm_import_flow.html" def get_context_data(self, **kwargs): context = super().get_context_data(**kwargs) context.update({'active_link' : 'adm-import'}) agency = Agency.objects.get(pk=kwargs.get("pk")) # Agency itself context.update({'agency' : agency}) # Users in that Agency context.update({'users' : User.objects.filter(profile__agency=agency)}) # DataFiles context.update({'files' : DataFile.objects.filter(agency=agency)}) # DataDirs context.update({'dirs' : DataDir.objects.filter(agency=agency).exclude(is_root=True)}) # Groups of the Agency groups = Group.objects.all() ag_pk = str(agency.pk) ag_groups = [] for g in groups: if(ag_pk in g.name): ag_groups.append(g) context.update({'groups' : ag_groups}) # LINK TO THE NC-INSTANCE context.update({'nclink' : settings.NEXTCLOUD_URL}) context.update({'ncid' : self.request.user.profile.nc_sid}) context.update({'nc_url' : settings.NEXTCLOUD_URL}) return context ''' Erstellt einen Gruppenordner ''' def createAgGroupFolder(request, agencypk): print("HI!") #agency = Agency.objects.get(pk=agencypk) #data = { # "gid" : "agencymaingroupid_" + str(agency.pk), # "aid" : str(agency.pk) #} r = requests.get(settings.NEXTCLOUD_URL + "apps/agency/createagf", auth=(settings.NEXTCLOUD_USER_API, settings.NEXTCLOUD_PW_API)) print(r.text) return JsonResponse({'status' : True, 'message': 'Gruppenordner angelegt!'})