Abrechnung auf monatlich umgestellt inkl. kündigung und wiederaufnahme

This commit is contained in:
holger.trampe 2020-10-02 18:07:28 +02:00
parent a2c60132cc
commit ac5c225ec1
9 changed files with 199 additions and 61 deletions

View File

@ -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)

View File

@ -3,17 +3,17 @@
{% load counter_tag %}
{% block content %}
<div class="content-section col-12">
<h3>Zahlplan abbestellen</h3>
<h3>Abonnement kündigen</h3>
<hr>
<form method="POST" enctype="multipart/form-data">
{% csrf_token %}
{{form|crispy}}
<p>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.</p>
<p>Sie können jederzeit einen neuen Zahlplan auswählen. Dieser beginnt dann frühestens nach dem Tag, an dem der aktuelle Plan ausläuft.</p>
<p>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.</p>
<p>Sie können jederzeit ein neues Abonnement starten. Dieser beginnt dann frühestens nach dem Tag, an dem das aktuelle Abonnement ausläuft.</p>
<hr>
<div class="col-8">
<a class="btn" href="{% url 'dasettings' %}">Abbrechen</a>
<button type="submit" class="btn btn-primary" style="float: right">Zahlplan abbestellen</button>&nbsp;
<button type="submit" class="btn btn-primary" style="float: right">Abonnement kündigen</button>&nbsp;
</div>
</form>
</div>

View File

@ -21,7 +21,7 @@
</tr>
<tr>
{% loadMWST user as mwst %}
<td>Gesetzliche MwSt. (19%)</td><td>{{mwst|floatformat:2|intcomma}} €</td>
<td>Gesetzliche MwSt. (16%)</td><td>{{mwst|floatformat:2|intcomma}} €</td>
</tr>
<tr>
<td>&nbsp;</td>
@ -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.
<br />
<a href="{% url 'ag-billplanupdate' request.user.profile.agency.pk %}" class="btn btn-primary btn mt-2" onclick="">Zahlplan jetzt auswählen</a>
{% 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.<br />
<a href="{% url 'ag-billplanupdate' request.user.profile.agency.pk %}" class="btn btn-primary btn mt-2" onclick="">Zahlplan jetzt auswählen</a>
<a href="{% url 'ag-billplanupdate' request.user.profile.agency.pk %}" class="btn btn-primary btn mt-2" onclick="">Abonnement starten</a>
{% 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.<br />
<a href="{% url 'ag-billplanupdate' request.user.profile.agency.pk %}" class="btn btn-primary btn mt-2" onclick="">Abonnement starten</a>
{% else %}
<br />
Ausgewählter Zahlungsplan: {{request.user.profile.agency.paymentplan}} Monat{% if request.user.profile.agency.paymentplan > 1 %}e{% endif %}<br />
Nächste Rechnungserstellung am {{bills.0.end|date:"d.m.Y"}}<br />
<a href="{% url 'ag-billplanend' request.user.profile.agency.pk %}" class="btn btn-primary btn mt-2" onclick="">Zahlplan abbestellen</a>
<a href="{% url 'ag-billplanend' request.user.profile.agency.pk %}" class="btn btn-primary btn mt-2" onclick="">Abonnement kündigen</a>
{% endif %}
<hr>
<h5 class="card-title.">Fragen, Hilfe, Kündigung</h5>

View File

@ -5,7 +5,7 @@
{% load counter_tag %}
{% block content %}
<div class="content-section col-12">
<h3>Zahlplan auswählen</h3>
<h3>Abonnement starten</h3>
<hr>
<form method="POST" enctype="multipart/form-data">
{% csrf_token %}
@ -21,42 +21,19 @@
</div>
<div class="col-4">
<h5>Zahlplan festlegen</h5>
<h5>Abonnement festlegen</h5>
<hr>
<p>Wählen Sie aus, für welchen Zeitraum die Abrechnung Ihrer Digitalen Agentur durchgeführt werden soll.</p>
<div class="form-check mt-2">
<input class="form-check-input" type="radio" name="planchoose" id="plan_1" value="1" onchange="javascript:updatePlan(1)">
<label class="form-check-label" for="plan_1">
1 Monate
</label>
</div>
<div class="form-check">
<input class="form-check-input" type="radio" name="planchoose" id="plan_2" value="3" onchange="javascript:updatePlan(3)">
<label class="form-check-label" for="plan_2">
3 Monate
</label>
</div>
<div class="form-check">
<input class="form-check-input" type="radio" name="planchoose" id="plan_3" value="6" checked onchange="javascript:updatePlan(6)"
<label class="form-check-label" for="plan_3">
6 Monate
</label>
</div>
<div class="form-check">
<input class="form-check-input" type="radio" name="planchoose" id="plan_4" value="12" onchange="javascript:updatePlan(12)">
<label class="form-check-label" for="plan_4">
12 Monate
</label>
</div>
<hr>
{{form.contract|as_crispy_field}}
{{form.agb|as_crispy_field}}
<p>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.
<hr>
<p>Mit Klick auf dem Button <i>Jetzt kostenpflichtig bestellen</i> 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.
<hr>
<b>Beginn des Leistungszeitraums: </b>{{start|date:"d.m.Y"}}<br />
<b>Beginn des Leistungszeitraums: </b>{{end|date:"d.m.Y"}}<br />
{% loadFinalMoney user as fm %}
<b>Rechnungsbetrag: <span id="billfinal">{{fm|floatformat:2|intcomma}}</span>&nbsp;</b>
<hr>
{{form.contract|as_crispy_field}}
{{form.agb|as_crispy_field}}
</div>
</div>
@ -75,7 +52,7 @@ var monthlybill_str = "{{fm}}";
var monthlybill = 0;
$(document).ready(function(){
monthlybill = monthlybill_str.replace(",", ".");
updatePlan(6);
updatePlan(1);
})

View File

@ -21,6 +21,11 @@
</div>
<small>*: Der Benutzer erhält direkt eine E-Mail mit einem Link zur Passworterstellung, wenn der Haken bei <i>E-Mailbenachrichtung schicken</i> gesetzt ist. Dies kann später auch wiederholt werden.</small>
{% if request.user.profile.agency.paymentplan != "0" %}
<hr>
<p>Der neu erstellte Nutzer wird zum nächsten Monat des Abrechnungszeitraums berechnet.</p>
{% endif %}
<hr>
<a class="btn" href="{% url 'dasettings' %} ">Abbrechen</a>
<button type="submit" class="btn btn-primary" style="float: right">Weiter zu Schritt 2</button>

View File

@ -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

View File

@ -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}'

View File

@ -39,6 +39,7 @@ urlpatterns = [
path('changeonlinestat/', views.changeonlinestat, name="users-updateonlinestat"),
path('dacron/<slug:code>', views.cronactions, name="cronmain"),
path('dacrondaily/<slug:code>', views.cronactionsdaily, name="cronmaindaily"),
path('dacronbill/<slug:code>', views.cronactionsbill, name="cronmainbill"),
path('isalive/', views.isAlive, name="isalive")
]

View File

@ -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