diff --git a/adm/forms.py b/adm/forms.py
new file mode 100644
index 0000000..55b6422
--- /dev/null
+++ b/adm/forms.py
@@ -0,0 +1,13 @@
+from django import forms
+from django.forms import ModelForm
+from users.models import AgencyBills
+
+class AgencyBillForm(forms.ModelForm):
+
+ class Meta:
+ model = AgencyBills
+ fields = ['agency', 'start']
+ labels = {
+ 'agency' : "Agentur",
+ 'start' : "Leistungszeitraum Start",
+ }
diff --git a/adm/templates/adm/adm_addbill.html b/adm/templates/adm/adm_addbill.html
new file mode 100644
index 0000000..7d291f4
--- /dev/null
+++ b/adm/templates/adm/adm_addbill.html
@@ -0,0 +1,42 @@
+{% extends "adm/adm_base.html" %}
+{% block content %}
+{% load adm_tags %}
+{% load mathfilters %}
+{% load crispy_forms_tags %}
+{% load humanize %}
+{% load counter_tag %}
+
+
Rechnung manuell erstellen
+
+Achtung! Sie sind in Begriff, eine Rechnung manuell zu erstellen! Achten Sie auf die korrekte Agentur sowie Start- und Endtermin! Prüfen Sie vor Anlagen Ihre Eingaben!
+
+
+
+{% endblock content %}
diff --git a/adm/templates/adm/adm_bills.html b/adm/templates/adm/adm_bills.html
index ef12bb2..6afd416 100644
--- a/adm/templates/adm/adm_bills.html
+++ b/adm/templates/adm/adm_bills.html
@@ -5,7 +5,11 @@
{% load humanize %}
{% load counter_tag %}
-
Rechungsübersicht
+
Rechungsübersicht
+
+ Rechnung
+
+
diff --git a/adm/urls.py b/adm/urls.py
index d633db6..5fcaf1e 100644
--- a/adm/urls.py
+++ b/adm/urls.py
@@ -16,5 +16,6 @@ urlpatterns = [
path('ag/bills/', AdmBills.as_view(), name="adm-bills"),
path('usersingle/', AdmUserSingle.as_view(), name="adm-user-single"),
path('cron/', statisticCronJob, name="adm-cron"),
- path('getorders/', getCSVRDOrders, name="getorders")
+ path('getorders/', getCSVRDOrders, name="getorders"),
+ path('adm/addbill', AdmAddBill.as_view(), name="admbill-add")
]
diff --git a/adm/views.py b/adm/views.py
index 7187342..e459bae 100644
--- a/adm/views.py
+++ b/adm/views.py
@@ -15,6 +15,17 @@ from datetime import date, datetime
import json
from users.models import UserYearAbsenceInfo, UserTime
from timemanagement.models import Workday, Absence
+from .forms import AgencyBillForm
+from datetime import date, timedelta
+
+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
'''
Prüfung, ob angemeldeter User Mitarbeiterstatus hat. IMMER PER DISPATCH EINBAUEN!
'''
@@ -121,6 +132,181 @@ class AdmBills(TemplateView):
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(days=30)
+ 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)
+
+ 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)
+ newbill.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
diff --git a/digitaleagentur/__pycache__/settings.cpython-38.pyc b/digitaleagentur/__pycache__/settings.cpython-38.pyc
index e4934a8..af75947 100644
Binary files a/digitaleagentur/__pycache__/settings.cpython-38.pyc and b/digitaleagentur/__pycache__/settings.cpython-38.pyc differ
diff --git a/dump.rdb b/dump.rdb
index fbe4324..46ac46e 100644
Binary files a/dump.rdb and b/dump.rdb differ
diff --git a/users/views.py b/users/views.py
index e028568..3761647 100644
--- a/users/views.py
+++ b/users/views.py
@@ -1480,40 +1480,37 @@ def cronactionsdaily(request, code):
'''
for user in allusers:
-
mailstatus += "\n USER: " + user.first_name + " " + user.last_name + " ID: (" + str(user.pk) + ")"
-
# REST URLAUB BERECHNUNG
- #try:
- usertimedata = UserTime.objects.get(user=user)
- day_tocheck = usertimedata.loose_holidedate.split(".")[0]
- month_tocheck = usertimedata.loose_holidedate.split(".")[1]
- month = today.month
- day = today.day
- if month < 10:
- month = "0" + str(month)
- day = today.day
- else:
- month = month
-
- if day < 10:
- day = "0" + str(day)
- else:
- day = day
-
- # Restetag erreicht, Reste ins nächste Jahr übertragen
- ''' DAS IST UNNÖTIG '''
- '''
- if(str(day_tocheck) == str(day) and str(month_tocheck) == str(month)):
- sourceyear = today.year
- this_year = list(UserYearAbsenceInfo.objects.filter(year=sourceyear, user=user))[0]
- next_year = list(UserYearAbsenceInfo.objects.filter(year=sourceyear+1, user=user))[0]
- next_year.restdays = this_year.days - this_year.days_inuse
- next_year.save()
- '''
-
- # Arbeitstage beenden
try:
+ usertimedata = UserTime.objects.get(user=user)
+ day_tocheck = usertimedata.loose_holidedate.split(".")[0]
+ month_tocheck = usertimedata.loose_holidedate.split(".")[1]
+ month = today.month
+ day = today.day
+ if month < 10:
+ month = "0" + str(month)
+ day = today.day
+ else:
+ month = month
+
+ if day < 10:
+ day = "0" + str(day)
+ else:
+ day = day
+
+ # Restetag erreicht, Reste ins nächste Jahr übertragen
+ ''' DAS IST UNNÖTIG '''
+ '''
+ if(str(day_tocheck) == str(day) and str(month_tocheck) == str(month)):
+ sourceyear = today.year
+ this_year = list(UserYearAbsenceInfo.objects.filter(year=sourceyear, user=user))[0]
+ next_year = list(UserYearAbsenceInfo.objects.filter(year=sourceyear+1, user=user))[0]
+ next_year.restdays = this_year.days - this_year.days_inuse
+ next_year.save()
+ '''
+
+ # Arbeitstage beenden
if(user.usertime.usetime):
try:
workdays = Workday.objects.filter(user=user, end=None)
@@ -1578,6 +1575,7 @@ def cronactionsdaily(request, code):
except ObjectDoesNotExist:
data.update({"status" + str(user.pk) : "no usertime found for " + user.get_full_name()})
mailstatus += "USER HAS NO USERTIMEOBJECT USER-ID: " + str(user.pk)
+
else:
data.update({"status" : "failed"})