From ac5c225ec14414843a66b81289155868996d388c Mon Sep 17 00:00:00 2001 From: "holger.trampe" Date: Fri, 2 Oct 2020 18:07:28 +0200 Subject: [PATCH] =?UTF-8?q?Abrechnung=20auf=20monatlich=20umgestellt=20ink?= =?UTF-8?q?l.=20k=C3=BCndigung=20und=20wiederaufnahme?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- dasettings/forms.py | 2 +- .../dasettings/bill_removepayplan.html | 8 +- .../templates/dasettings/calc_content.html | 17 +- .../dasettings/dasettings_billplan.html | 41 ++--- .../dasettings/user_newuser_step1.html | 5 + dasettings/views.py | 28 ++-- users/models.py | 8 +- users/urls.py | 1 + users/views.py | 150 +++++++++++++++++- 9 files changed, 199 insertions(+), 61 deletions(-) diff --git a/dasettings/forms.py b/dasettings/forms.py index 0fcfde6..96ce513 100644 --- a/dasettings/forms.py +++ b/dasettings/forms.py @@ -63,7 +63,7 @@ class AgencyBillPlan(forms.ModelForm): def __init__(self, *args, **kwargs): super(AgencyBillPlan, self).__init__(*args, **kwargs) - self.fields['paymentplan'] = forms.CharField(initial=6, required=True, widget=forms.HiddenInput()) + self.fields['paymentplan'] = forms.CharField(initial=1, required=True, widget=forms.HiddenInput()) self.fields['lexofficeid'] = forms.CharField(initial="", required=False, widget=forms.HiddenInput()) self.fields['name'] = forms.CharField(required=True) diff --git a/dasettings/templates/dasettings/bill_removepayplan.html b/dasettings/templates/dasettings/bill_removepayplan.html index 982bdcf..cc55fdf 100644 --- a/dasettings/templates/dasettings/bill_removepayplan.html +++ b/dasettings/templates/dasettings/bill_removepayplan.html @@ -3,17 +3,17 @@ {% load counter_tag %} {% block content %}
-

Zahlplan abbestellen

+

Abonnement kündigen


{% csrf_token %} {{form|crispy}} -

Bestellen Sie den Zahlplan ab, erhalten Sie keine automatische Verlängerung. Beachten Sie, dass sich Ihre Mitarbeiter spätestens zwei Wochen nach dem letzten Tag des bezahlten Zeitraums Ihre Digitale Agentur nicht mehr anmelden können.

-

Sie können jederzeit einen neuen Zahlplan auswählen. Dieser beginnt dann frühestens nach dem Tag, an dem der aktuelle Plan ausläuft.

+

Beenden Sie das Abonnement, erhalten Sie keine automatische Verlängerung. Beachten Sie, dass sich Ihre Mitarbeiter spätestens zwei Wochen nach dem letzten Tag des bezahlten Zeitraums Ihre Digitale Agentur nicht mehr anmelden können.

+

Sie können jederzeit ein neues Abonnement starten. Dieser beginnt dann frühestens nach dem Tag, an dem das aktuelle Abonnement ausläuft.


Abbrechen -   +  
diff --git a/dasettings/templates/dasettings/calc_content.html b/dasettings/templates/dasettings/calc_content.html index d9c4bbf..ec6991c 100644 --- a/dasettings/templates/dasettings/calc_content.html +++ b/dasettings/templates/dasettings/calc_content.html @@ -21,7 +21,7 @@ {% loadMWST user as mwst %} - Gesetzliche MwSt. (19%){{mwst|floatformat:2|intcomma}} € + Gesetzliche MwSt. (16%){{mwst|floatformat:2|intcomma}} €   @@ -36,18 +36,17 @@ {% getNextMonth request.user.profile.agency as nextMonth %} Ihre Agentur wurde am {{ request.user.profile.agency.registerdate|date:"d.m.Y" }} registriert. - {% if paymentplan == None and bills|length == 0 %} - Es wurde noch keine Zahlungsweise ausgewählt und keine Rechnungen gefunden. Sie können die Digitale Agentur bis zum {{nextMonth|date:"d.m.Y"}} kostenlos nutzen. Möchten Sie die Digitale Agentur auch nach diesem Zeitraum nutzen, wählen Sie bitte einen Zahlplan aus. + {% if bills|length == 0 %} + Es wurde noch kein Abonnement gestartet und keine Rechnungen gefunden. Sie können die Digitale Agentur bis zum {{nextMonth|date:"d.m.Y"}} kostenlos nutzen. Möchten Sie die Digitale Agentur auch nach diesem Zeitraum nutzen, starten Sie bitte ein neues Abonnement.
- Zahlplan jetzt auswählen - {% elif bills|length > 0 and request.user.profile.agency.paymentplan == None %} - Ihre aktuelle Rechnungen erlaubt Ihnen die Nutzung der digitalen Agentur bis zum {{bills.0.end|date:"d.m.Y"}}. Danach wird der Zugang gesperrt. Legen Sie einen neuen Zahlplan fest, um die digitale Agentur auch weiterhin zu nutzen.
- Zahlplan jetzt auswählen + Abonnement starten + {% elif bills|length > 0 and request.user.profile.agency.paymentplan == 0 %} + Ihre aktuelle Rechnungen erlaubt Ihnen die Nutzung der digitalen Agentur bis zum {{bills.0.end|date:"d.m.Y"}}. Danach wird der Zugang gesperrt. Starten Sie ein neues Abonnement, um die digitale Agentur auch weiterhin zu nutzen.
+ Abonnement starten {% else %}
- Ausgewählter Zahlungsplan: {{request.user.profile.agency.paymentplan}} Monat{% if request.user.profile.agency.paymentplan > 1 %}e{% endif %}
Nächste Rechnungserstellung am {{bills.0.end|date:"d.m.Y"}}
- Zahlplan abbestellen + Abonnement kündigen {% endif %}
Fragen, Hilfe, Kündigung
diff --git a/dasettings/templates/dasettings/dasettings_billplan.html b/dasettings/templates/dasettings/dasettings_billplan.html index fc24071..8748e56 100644 --- a/dasettings/templates/dasettings/dasettings_billplan.html +++ b/dasettings/templates/dasettings/dasettings_billplan.html @@ -5,7 +5,7 @@ {% load counter_tag %} {% block content %}
-

Zahlplan auswählen

+

Abonnement starten


{% csrf_token %} @@ -21,42 +21,19 @@
-
Zahlplan festlegen
+
Abonnement festlegen

-

Wählen Sie aus, für welchen Zeitraum die Abrechnung Ihrer Digitalen Agentur durchgeführt werden soll.

-
- - -
-
- - -
-
- - 6 Monate - -
-
- - -
-
- {{form.contract|as_crispy_field}} - {{form.agb|as_crispy_field}} +

Das Abonnement der digitalen Agentur umfasst die Nutzung inkl. der aktuellen Nutzeranzahl über einen Monat. Nach jedem Monat wird eine neue Rechnung generiert, um die aktuelle Nutzeranzahl zu erfassen. Sie können innerhalb des Monats ihr Abonnement kündigen. +


Mit Klick auf dem Button Jetzt kostenpflichtig bestellen wird eine Rechnung für Ihre Agentur generiert und per E-Mail an die hinterlegte Rechnungs-E-Mailadresse oder an die Agentur-E-Mailadresse versendet. Der Rechnungsbetrag muss innerhalb von 14 Tagen beglichen werden.


- Beginn des Leistungszeitraums: {{start|date:"d.m.Y"}}
+ Beginn des Leistungszeitraums: {{end|date:"d.m.Y"}}
{% loadFinalMoney user as fm %} Rechnungsbetrag: {{fm|floatformat:2|intcomma}} € +
+ {{form.contract|as_crispy_field}} + {{form.agb|as_crispy_field}}
@@ -75,7 +52,7 @@ var monthlybill_str = "{{fm}}"; var monthlybill = 0; $(document).ready(function(){ monthlybill = monthlybill_str.replace(",", "."); - updatePlan(6); + updatePlan(1); }) diff --git a/dasettings/templates/dasettings/user_newuser_step1.html b/dasettings/templates/dasettings/user_newuser_step1.html index e1f1c87..eb89e0b 100644 --- a/dasettings/templates/dasettings/user_newuser_step1.html +++ b/dasettings/templates/dasettings/user_newuser_step1.html @@ -21,6 +21,11 @@ *: Der Benutzer erhält direkt eine E-Mail mit einem Link zur Passworterstellung, wenn der Haken bei E-Mailbenachrichtung schicken gesetzt ist. Dies kann später auch wiederholt werden. + {% if request.user.profile.agency.paymentplan != "0" %} +
+

Der neu erstellte Nutzer wird zum nächsten Monat des Abrechnungszeitraums berechnet.

+ {% endif %} +
Abbrechen diff --git a/dasettings/views.py b/dasettings/views.py index a57989d..e552c86 100644 --- a/dasettings/views.py +++ b/dasettings/views.py @@ -255,12 +255,12 @@ def DASettings(request): 'Accept': 'application/json', } - json_data = json.dumps(lexdata) - r = requests.get("https://api.lexoffice.io/v1/invoices/"+AgencyBills.objects.filter(agency=request.user.profile.agency)[0].lexid, data=json_data, headers=headers) + #json_data = json.dumps(lexdata) + #r = requests.get("https://api.lexoffice.io/v1/invoices/"+AgencyBills.objects.filter(agency=request.user.profile.agency)[0].lexid, data=json_data, headers=headers) #json.loads(r.text) - print(r.text) + #print(r.text) # Alle Rechnungen der Agentur abfragen - context.update({"bills" : AgencyBills.objects.filter(agency=request.user.profile.agency).order_by("billdate")}) + context.update({"bills" : AgencyBills.objects.filter(agency=request.user.profile.agency).order_by("-end")}) return render(request, 'dasettings/settings.html', context) @@ -1558,8 +1558,8 @@ class BillPlanEnd(UpdateView): template_name = "dasettings/bill_removepayplan.html" def form_valid(self, form): - self.object.paymentplan = None - messages.success(self.request, f"Zahlplan abbestellt!") + self.object.paymentplan = 0 + messages.success(self.request, f"Abonnement gekündigt!") return super().form_valid(form) @@ -1579,6 +1579,8 @@ class BillPlanUpdate(UpdateView): # Wenn die Agentur noch KEINE Lexoffice-ID hat, dann ist der Freimonat noch nicht durch. if agency.lexofficeid == "": month = month + relativedelta(months=1) + else: + month = AgencyBills.objects.filter(agency=self.request.user.profile.agency).order_by("-end")[0].end next_month = month + relativedelta(months=1) @@ -1698,7 +1700,7 @@ class BillPlanUpdate(UpdateView): if len(agency.lexofficeid) == 0: self.object.lexofficeid = response_text["organizationId"] - 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) + 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() self.object.save() @@ -1708,10 +1710,10 @@ class BillPlanUpdate(UpdateView): else: mail_to_send = self.request.user.profile.agency.payment_address - print(mail_to_send) + msg_html = render_to_string('users/newbill_mail.html', {}) - send_mail('Digitale Agentur | Rechnung', 'Sehr geehrte Nutzer, es wurde eine Rechnung für Ihre digitale Agentur erstellt. Diese können Sie unter Einstellungen, Abrechnung einsehen.','noreply@digitale-agentur.com',[mail_to_send],html_message=msg_html,fail_silently=False) + send_mail('Digitale Agentur | Rechnung', 'Sehr geehrte Nutzer, es wurde eine Rechnung für Ihre digitale Agentur erstellt. Diese können Sie unter Einstellungen, Abrechnung einsehen.','noreply@digitale-agentur.com',[mail_to_send],html_message=msg_html,fail_silently=True) else: messages.warning(self.request, f"Fehlercode "+str(r.status_code)+". Es wurde keine Rechnung erstellt. Bitte wenden Sie sich an den Support!") @@ -1725,14 +1727,18 @@ class BillPlanUpdate(UpdateView): # Rechnungsbegin setzen agency = self.request.user.profile.agency - month = agency.registerdate + + if len(AgencyBills.objects.filter(agency=self.request.user.profile.agency)) == 0: + month = self.request.user.profile.agency.registerdate + relativedelta(months=1) + else: + month = AgencyBills.objects.filter(agency=self.request.user.profile.agency).order_by("-end")[0].end # Wenn die Agentur noch KEINE Lexoffice-ID hat, dann ist der Freimonat noch nicht durch. if agency.lexofficeid == "": month = month + relativedelta(months=1) - context.update({'active_link' : 'dasettings', 'start' : month}) + context.update({'active_link' : 'dasettings', 'end' : month}) return context diff --git a/users/models.py b/users/models.py index 39697f9..05b98be 100644 --- a/users/models.py +++ b/users/models.py @@ -98,8 +98,9 @@ class Agency(models.Model): # ID für die Verbindung mit Lexoffice lexofficeid = models.CharField(default="", max_length=200, blank=True) - # Bezahlplan 3,6,12 Monate - paymentplan = models.IntegerField(default=None, null=True, blank=True) + # Bezahlplan 1,3,6,12 Monate + #0 = Kein Bezahkplan ausgewählt + paymentplan = models.IntegerField(default=0, null=True, blank=True) # Registrierdatum der Agentur registerdate = models.DateField(default=timezone.now, null=True) @@ -157,7 +158,8 @@ class AgencyBills(models.Model): start = models.DateField(default=timezone.now) end = models.DateField(default=timezone.now) plan = models.CharField(default="", max_length=20) - + usercount = models.IntegerField(default=0) + def __str__(self): return f'{self.lexid}' diff --git a/users/urls.py b/users/urls.py index 890fde2..7dd33a1 100644 --- a/users/urls.py +++ b/users/urls.py @@ -39,6 +39,7 @@ urlpatterns = [ path('changeonlinestat/', views.changeonlinestat, name="users-updateonlinestat"), path('dacron/', views.cronactions, name="cronmain"), path('dacrondaily/', views.cronactionsdaily, name="cronmaindaily"), + path('dacronbill/', views.cronactionsbill, name="cronmainbill"), path('isalive/', views.isAlive, name="isalive") ] diff --git a/users/views.py b/users/views.py index 4d4d6c4..06adf93 100644 --- a/users/views.py +++ b/users/views.py @@ -7,7 +7,7 @@ from django.views.generic import CreateView, ListView, UpdateView, DetailView, D from django.contrib import messages from django.contrib.auth.models import User, Permission from django.db import models -from .models import Profile, Agency, UserTime, UserYearAbsenceInfo +from .models import Profile, Agency, UserTime, UserYearAbsenceInfo, AgencyBills from django.core.mail import send_mail from django.http import HttpResponseRedirect,HttpResponse, JsonResponse from areas.models import Areas @@ -1136,6 +1136,154 @@ def cronactionsdaily(request, code): return JsonResponse(data) +''' + ABRECHNUNG CRON JOB + +''' +from dateutil.relativedelta import * +def cronactionsbill(request, code): + data = {} + if(code == settings.CRONAPIKEY): + today = date.today() + # Check, ob Rechnungen bezahlt wurden + unpaid_bills = AgencyBills.objects.filter(billstatus="open") + + for bill in unpaid_bills: + # Für jede Rechnung eine Anfrage an die LexOffice API und voucherStatus auslesen + headers = { + 'Authorization': 'Bearer ' + settings.LEX_API, + 'Content-Type': 'application/json', + 'Accept': 'application/json', + } + + json_data = {} + + r = requests.get("https://api.lexoffice.io/v1/invoices/"+AgencyBills.objects.get(pk=bill.pk).lexid, data=json_data, headers=headers) + if(json.loads(r.text)["voucherStatus"] == "paid"): + bill.billstatus="paid" + bill.save() + + # Monatliche Berechnung + # Alle Rechnungen laden, deren Letzter Tag HEUTE ist und bei ausgewähltem Paymentplan 1 eine neue Rechnung erstellen, Mailverschicke, Nutzeraccouns zählen und neue Rechnung in der Agentur hinterlegen + new_bills = AgencyBills.objects.filter(end=today) + for bill in new_bills: + if bill.agency.paymentplan == 1: + + agency = bill.agency + + month = today + + next_month = today + relativedelta(months=1) + # 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 = month + start_date_string = month.strftime("%d.%m.%Y") + end_date = month + relativedelta(months=plan) + end_date_string= end_date.strftime("%d.%m.%Y") + + 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" : 16 + }, + }, + { + "type" : "custom", + "name" : "Digitale Agentur: Zusätzliche Mitarbeiter", + "description" : "Zeitraum " + start_date_string + " - " + end_date_string, + "quantity" : usercount, + "unitName" : "Stück", + "unitPrice" : + { + "currency" : "EUR", + "netAmount" : 3, + "taxRatePercentage" : 16 + }, + } + ], + "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) + + r = requests.post("https://api.lexoffice.io/v1/invoices/?finalize=true", data=json_data, headers=headers) + + if(r.status_code == 201): + messages.success(request, f"Rechnung erstellt!") + # Response in JSON umwandeln + + 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 == ""): + mail_to_send = agency.agency_email + else: + mail_to_send = agency.payment_address + msg_html = render_to_string('users/newbill_mail.html', {}) + send_mail('Digitale Agentur | Rechnung', 'Sehr geehrte Nutzer, es wurde eine Rechnung für Ihre digitale Agentur erstellt. Diese können Sie unter Einstellungen, Abrechnung einsehen.','noreply@digitale-agentur.com',[mail_to_send],html_message=msg_html,fail_silently=True) + data.update({"newBill_" + str(agency.pk) : newbill.lexid}) + else: + data.update({"status" : "failed"}) + return JsonResponse(data) + + + def sendMailNoti(notificationtext, user_touched, linktarget=""): username = user_touched.first_name + " " + user_touched.last_name