560 lines
17 KiB
Python
560 lines
17 KiB
Python
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
|
|
from recoverdir.models import *
|
|
from .forms import AgencyBillForm
|
|
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):
|
|
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')[:180] })
|
|
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()})
|
|
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
|
|
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
|
|
|
|
# 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()
|
|
|
|
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)
|
|
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])
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|