Abrechnung

This commit is contained in:
holger.trampe 2020-10-01 09:20:54 +02:00
parent a6fb6bed60
commit 4e3f916ffb
11 changed files with 134 additions and 35 deletions

View File

@ -58,13 +58,15 @@ class AgencyBillPlan(forms.ModelForm):
"phone" : "Telefon", "phone" : "Telefon",
"agb" : "AGB akzeptieren", "agb" : "AGB akzeptieren",
"contract" : "Auftragsdatenverarbeitung akzeptieren" "contract" : "Auftragsdatenverarbeitung akzeptieren"
} }
fields = ['name','inhaber','agency_email', 'phone', 'street', 'plz', 'city', 'paymentplan', 'agb', 'contract'] fields = ['name','inhaber','agency_email', 'phone', 'street', 'plz', 'city', 'paymentplan', 'agb', 'contract', 'lexofficeid', 'firstbillid']
def __init__(self, *args, **kwargs): def __init__(self, *args, **kwargs):
super(AgencyBillPlan, self).__init__(*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=6, required=True, widget=forms.HiddenInput())
self.fields['lexofficeid'] = forms.CharField(initial="", required=False, widget=forms.HiddenInput())
self.fields['firstbillid'] = forms.CharField(initial="", required=False, widget=forms.HiddenInput())
self.fields['name'] = forms.CharField(required=True) self.fields['name'] = forms.CharField(required=True)
self.fields['inhaber'] = forms.CharField(required=True) self.fields['inhaber'] = forms.CharField(required=True)

View File

@ -35,10 +35,10 @@
<h5 class="card-title">Ihre Zahlungsweise</h5> <h5 class="card-title">Ihre Zahlungsweise</h5>
{% getNextMonth request.user.profile.agency as nextMonth %} {% getNextMonth request.user.profile.agency as nextMonth %}
{{request.user.profile.agency.firstbillid}}
Ihre Agentur wurde am {{ request.user.profile.agency.registerdate|date:"d.m.Y" }} registriert. Ihre Agentur wurde am {{ request.user.profile.agency.registerdate|date:"d.m.Y" }} registriert.
{% if paymentplan == None %} {% if paymentplan == None and request.user.profile.agency.firstbillid == None %}
Es wurde noch keine Zahlungsweise ausgewählt. 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. Es wurde noch keine Zahlungsweise ausgewählt. 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.
<br /> <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="">Zahlplan jetzt auswählen</a>

View File

@ -25,20 +25,26 @@
<hr> <hr>
<p>Wählen Sie aus, für welchen Zeitraum die Abrechnung Ihrer Digitalen Agentur durchgeführt werden soll.</p> <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"> <div class="form-check mt-2">
<input class="form-check-input" type="radio" name="planchoose" id="plan_1" value="3" onchange="javascript:updatePlan(3)"> <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"> <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 3 Monate
</label> </label>
</div> </div>
<div class="form-check"> <div class="form-check">
<input class="form-check-input" type="radio" name="planchoose" id="plan_2" value="6" checked onchange="javascript:updatePlan(6)" <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"> <label class="form-check-label" for="plan_3">
6 Monate 6 Monate
</label> </label>
</div> </div>
<div class="form-check"> <div class="form-check">
<input class="form-check-input" type="radio" name="planchoose" id="plan_3" value="12" onchange="javascript:updatePlan(12)"> <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_3"> <label class="form-check-label" for="plan_4">
12 Monate 12 Monate
</label> </label>
</div> </div>

View File

@ -242,6 +242,27 @@ def DASettings(request):
agencyform = AgencyUpdateForm(instance=request.user.profile.agency) agencyform = AgencyUpdateForm(instance=request.user.profile.agency)
context.update({'agencyform' : agencyform}) context.update({'agencyform' : agencyform})
# Abrechnung BILLS
# TEST ID
# TODO: Hier Rechnungen der Agentur laden
lexdata = {}
# HEADERS CURL
headers = {
'Authorization': 'Bearer 8f9ba01f-9e84-42c7-9548-48c254f14c19',
'Content-Type': 'application/json',
'Accept': 'application/json',
}
json_data = json.dumps(lexdata)
r = requests.get("https://api.lexoffice.io/v1/invoices/ad75e041-1657-43a3-b3cb-7349aa00a94f", data=json_data, headers=headers)
return render(request, 'dasettings/settings.html', context) return render(request, 'dasettings/settings.html', context)
''' '''
@ -1470,13 +1491,6 @@ class BillPlanUpdate(UpdateView):
def form_valid(self, form): def form_valid(self, form):
agency = self.request.user.profile.agency agency = self.request.user.profile.agency
# HEADERS CURL
headers = {
'Authorization': 'Bearer 33bfb1b9-2994-4fd4-b447-1f4754a5c7cb',
'Content-Type': 'application/json',
'Accept': 'application/json',
}
month = agency.registerdate month = agency.registerdate
next_month = month + relativedelta(months=1) next_month = month + relativedelta(months=1)
@ -1490,11 +1504,41 @@ class BillPlanUpdate(UpdateView):
else: else:
usercount = usercount - 3 usercount = usercount - 3
# HEADERS CURL
headers = {
'Authorization': 'Bearer 8f9ba01f-9e84-42c7-9548-48c254f14c19',
'Content-Type': 'application/json',
'Accept': 'application/json',
}
plan = int(form.cleaned_data['paymentplan'])
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")
# TODO: Nachgebuchte Mitarbeiter
# TODO: Was passiert bei Änderungen der Agenturdaten?
# TODO: Kündigungsmöglichkeit, den Zahlplan zu beenden
# DataJSON # DataJSON
'''
Bei Beschreibung noch Zeitraum vom XX.XX.XXXX bis XX.XX.XXXX
'''
monthword = "Monate"
if form.cleaned_data['paymentplan'] == "1":
monthword = "Monat"
lexdata = { lexdata = {
"voucherDate": voucher_date + "T00:00:00.000+01:00", "voucherDate": voucher_date + "T00:00:00.000+00:00",
"address" : { "address" : {
"name" : agency.name, "name" : agency.name,
"street": agency.street,
"zip": agency.plz,
"city": agency.city,
"countryCode" : "DE" "countryCode" : "DE"
}, },
"totalPrice" : { "totalPrice" : {
@ -1503,46 +1547,76 @@ class BillPlanUpdate(UpdateView):
"lineItems" : [ "lineItems" : [
{ {
"type" : "custom", "type" : "custom",
"name" : "Monatsbeitrag", "name" : "Digitale Agentur: Grundbetrag für " + str(plan) + " " + monthword,
"quantity" : form.cleaned_data['paymentplan'], "quantity" : 1,
"unitName" : "Stück", "unitName" : "Anzahl",
"description" : "Zeitraum " + start_date_string + " - " + end_date_string,
"unitPrice" : "unitPrice" :
{ {
"currency" : "EUR", "currency" : "EUR",
"netAmount" : 21.00, "netAmount" : 21.00 * int(form.cleaned_data['paymentplan']),
"taxRatePercentage" : 19 "taxRatePercentage" : 16
}, },
}, },
{ {
"type" : "custom", "type" : "custom",
"name" : "Weitere Mitarbeiter", "name" : "Digitale Agentur: Zusätzliche Mitarbeiter",
"description" : "Zeitraum " + start_date_string + " - " + end_date_string,
"quantity" : usercount, "quantity" : usercount,
"unitName" : "Stück", "unitName" : "Anzahl",
"unitPrice" : "unitPrice" :
{ {
"currency" : "EUR", "currency" : "EUR",
"netAmount" : 3, "netAmount" : 3 * int(form.cleaned_data['paymentplan']),
"taxRatePercentage" : 19 "taxRatePercentage" : 16
}, },
} }
], ],
"taxConditions": { "taxConditions": {
"taxType": "net" "taxType": "net"
}, },
"paymentConditions": {
"paymentTermLabel": "Bitte zahlen Sie innerhalb von 14 Tagen.",
"paymentTermDuration": 14,
},
"shippingConditions": { "shippingConditions": {
"shippingDate": voucher_date + "T00:00:00.000+01:00", "shippingDate": voucher_date + "T00:00:00.000+00:00",
"shippingType": "service" "shippingType": "service"
}, },
} }
json_data = json.dumps(lexdata) json_data = json.dumps(lexdata)
r = requests.post("https://api.lexoffice.io/v1/vouchers", data=json_data, headers=headers) self.object = form.save(commit=False)
if(r.status_code != 200): r = requests.post("https://api.lexoffice.io/v1/invoices", data=json_data, headers=headers)
if(r.status_code == 201):
messages.success(self.request, f"Rechnung erstellt!")
# Response in JSON umwandeln
response_text = json.loads(r.text)
# Rechnungsidee speichern
self.object.firstbillid = response_text["id"]
# HEADERS CURL
headers = {
'Authorization': 'Bearer 8f9ba01f-9e84-42c7-9548-48c254f14c19',
'Content-Type': 'application/json',
'Accept': 'application/json',
}
json_data = json.dumps(lexdata)
if len(agency.lexofficeid) == 0:
# 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)
self.object.lexofficeid = response_text["organizationId"]
self.object.save()
else:
messages.warning(self.request, f"Fehlercode "+str(r.status_code)+". Es wurde keine Rechnung erstellt. Bitte wenden Sie sich an den Support!") messages.warning(self.request, f"Fehlercode "+str(r.status_code)+". Es wurde keine Rechnung erstellt. Bitte wenden Sie sich an den Support!")
print(r.status_code)
return super().form_valid(form) return super().form_valid(form)

View File

@ -1081,7 +1081,18 @@ $(document).ready(function() {
$('#id_content').summernote({ $('#id_content').summernote({
height: 400, height: 400,
lang: "de-DE", lang: "de-DE",
disableDragAndDrop: true disableDragAndDrop: true,
/* TASK: Hier Fontsize zzgl zu den anderen machen, damit das auch geht */
/*
toolbar: [
['style', ['style']],
['text', ['bold', 'italic', 'underline', 'color', 'clear']],
['para', ['ul', 'ol', 'paragraph']],
['height', ['height']],
['fontsize', ['fontsize']],
['font', ['fontname']],
],
*/
}); });
}); });

View File

@ -827,7 +827,7 @@ $("#id_area").change(function () {
$(document).ready(function() { $(document).ready(function() {
$('#id_content').summernote({ $('#id_content').summernote({
lang: "de-DE", lang: "de-DE",
height: 400, height: 100,
disableDragAndDrop: true disableDragAndDrop: true
}); });
}); });

View File

@ -715,7 +715,7 @@ def loadMWST(user):
else: else:
usercount = usercount - 3 usercount = usercount - 3
mwst = (21.0 + usercount*3)/100 * 19 mwst = (21.0 + usercount*3)/100 * 16
return mwst return mwst
@ -728,8 +728,7 @@ def loadFinalMoney(user):
else: else:
usercount = usercount - 3 usercount = usercount - 3
finalMoney = ((21.0 + usercount*3)/100 * 19) + 21.0 + usercount*3 finalMoney = (21.0 + usercount*3) * 1.16
return finalMoney return finalMoney

View File

@ -98,6 +98,9 @@ class Agency(models.Model):
# ID für die Verbindung mit Lexoffice # ID für die Verbindung mit Lexoffice
lexofficeid = models.CharField(default="", max_length=200, blank=True) lexofficeid = models.CharField(default="", max_length=200, blank=True)
# First Bill id to retrieve office-organization-id
firstbillid = models.CharField(default=None, max_length=200, blank=True, null=True)
# Bezahlplan 3,6,12 Monate # Bezahlplan 3,6,12 Monate
paymentplan = models.IntegerField(default=None, null=True, blank=True) paymentplan = models.IntegerField(default=None, null=True, blank=True)

View File

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

View File

@ -1148,3 +1148,6 @@ def sendMailNoti(notificationtext, user_touched, linktarget=""):
html_message=msg_html, html_message=msg_html,
fail_silently=True fail_silently=True
) )
def isAlive(request):
return JsonResponse({"status" : True})