PDF Rechnung fertig

This commit is contained in:
holger.trampe 2020-10-02 00:12:57 +02:00
parent 8b106c569c
commit 91114eea82
6 changed files with 96 additions and 27 deletions

View File

@ -0,0 +1,8 @@
{% extends "users/base.html" %}
{% block content %}
<div class="content-section col-12">
<h3>Rechnung betrachten</h3>
<hr>
<a href="{% url 'ag-getbillpdf' bill.pk %}" target="_blank">Hier herunterladen</a>
</div>
{% endblock content %}

View File

@ -37,19 +37,21 @@
{% getNextMonth request.user.profile.agency as nextMonth %} {% getNextMonth request.user.profile.agency as nextMonth %}
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 == "" or request.user.profile.agency.lexofficeid == "" %} {% if paymentplan == "" %}
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>
{% else %} {% else %}
<br />Ausgewählter Zahlungsplan: {{request.user.profile.agency.paymentplan}} Monat{% if request.user.profile.agency.paymentplan > 1 %}e{% endif %} <br /> <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="#" class="btn btn-primary btn mt-2" onclick="">Zahlplan abbestellen</a> <a href="#" class="btn btn-primary btn mt-2" onclick="">Zahlplan abbestellen</a>
{% endif %} {% endif %}
<hr> <hr>
<h5 class="card-title.">Fragen, Hilfe, Kündigung</h5> <h5 class="card-title.">Fragen, Hilfe, Kündigung</h5>
Bei Fragen zu Ihrer Abrechnung melden Sie sich bitte per E-Mail an <a href="mailto:abrechnung@digitale-agentur.com">abrechnung@digitale-agentur.com</a>. Bei Fragen zu Ihrer Abrechnung melden Sie sich bitte per E-Mail an <a href="mailto:abrechnung@digitale-agentur.com">abrechnung@digitale-agentur.com</a>.
<!-- TASK: Kündigungsmodaliäten einfügen --> <!-- TASK: Kündigungsmodaliäten einfügen -->
KÜNDIGUNGSMODALITÄTEN NOCH EINFÜGEN Die Kündigungsmodalitäten finden Sie in den AGB's. Alternativ wenden Sie sich an den Support.
</div> </div>
</div> </div>
</div> </div>
@ -73,7 +75,7 @@
<div class="card-body"> <div class="card-body">
<h5 class="card-title">Rechnungen</h5> <h5 class="card-title">Rechnungen</h5>
{% for bill in bills %} {% for bill in bills %}
<a href="{{bill.lexid}}">Rechnung vom {{bill.billdate|date:"d.m.Y"}} (Nr. {{bill.billnumber}})</a><br /> <a href="{% url 'ag-getbillpdf' bill.pk %}" target="_blank">Rechnung vom {{bill.billdate|date:"d.m.Y"}} ({{bill.billnumber}})</a> - {% if bill.billstatus == "open" %} Offen {% elif bill.billstatus == "paid" %} Bezahlt {% endif %} <br />
{% endfor %} {% endfor %}
</div> </div>
</div> </div>

View File

@ -3,7 +3,7 @@ from django.contrib.auth import views as auth_views
from django.contrib.auth.decorators import login_required, permission_required from django.contrib.auth.decorators import login_required, permission_required
from . import views from . import views
from .views import FreeDayDeleteView, AbsenceReasonDeleteView, AbsenceReasonUpdateView, AbsenceReasonAddView from .views import FreeDayDeleteView, AbsenceReasonDeleteView, AbsenceReasonUpdateView, AbsenceReasonAddView
from .views import NewUserFirstStep, UserProfileUpdate, UserChangeMain, BillMailUpdate, BillPlanUpdate from .views import NewUserFirstStep, UserProfileUpdate, UserChangeMain, BillMailUpdate, BillPlanUpdate, GetBill, GetBillPDF
''' '''
Permissions definiert in models.py bei USERS und dann hier vor die View geschrieben! Permissions definiert in models.py bei USERS und dann hier vor die View geschrieben!
''' '''
@ -35,6 +35,7 @@ urlpatterns = [
path('abcatadd/', AbsenceReasonAddView.as_view(), name="abcat-add"), path('abcatadd/', AbsenceReasonAddView.as_view(), name="abcat-add"),
path('ag/billmail/update/<int:pk>', permission_required('users.agencyinfo')(BillMailUpdate.as_view()), name='ag-billmailupdate'), path('ag/billmail/update/<int:pk>', permission_required('users.agencyinfo')(BillMailUpdate.as_view()), name='ag-billmailupdate'),
path('ag/billplan/<int:pk>', permission_required('users.agencyinfo')(BillPlanUpdate.as_view()), name='ag-billplanupdate'), path('ag/billplan/<int:pk>', permission_required('users.agencyinfo')(BillPlanUpdate.as_view()), name='ag-billplanupdate'),
#path('ag/getbill/<slug:billid>', permission_required('users.agencyinfo')(GetBill), name='ag-getbill'), path('ag/getbill/<int:pk>', permission_required('users.agencyinfo')(GetBill), name='ag-getbill'),
path('ag/getbillpdf/<int:pk>', permission_required('users.agencyinfo')(GetBillPDF), name='ag-getbillpdf'),
] ]

View File

@ -259,15 +259,70 @@ def DASettings(request):
# Alle Rechnungen der Agentur abfragen # Alle Rechnungen der Agentur abfragen
context.update({"bills" : AgencyBills.objects.filter(agency=request.user.profile.agency)}) context.update({"bills" : AgencyBills.objects.filter(agency=request.user.profile.agency).order_by("billdate")})
#r = requests.get("https://api.lexoffice.io/v1/invoices/" + AgencyBills.objects.filter(agency=request.user.profile.agency)[0].lexid, data=json_data, headers=headers)
return render(request, 'dasettings/settings.html', context) return render(request, 'dasettings/settings.html', context)
from django.http import FileResponse, Http404
@login_required
def GetBill(request, pk):
# HEADERS CURL
headers = {
'Authorization': 'Bearer 8f9ba01f-9e84-42c7-9548-48c254f14c19',
'Content-Type': 'application/json',
'Accept': 'application/json',
}
json_data = {}
r = requests.get("https://api.lexoffice.io/v1/invoices/"+AgencyBills.objects.get(pk=pk).lexid+"/document", data=json_data, headers=headers)
context = {
'active_link' : 'dasettings',
'bill' : AgencyBills.objects.get(pk=pk),
'fileid' : json.loads(r.text)["documentFileId"]
}
return render(request, 'dasettings/bill_single.html', context)
from fpdf import FPDF, HTMLMixin
class HtmlPdf(FPDF, HTMLMixin):
pass
import io as BytesIO
import base64
from django.http import HttpResponse
@login_required
def GetBillPDF(request, pk):
headers = {
'Authorization': 'Bearer 8f9ba01f-9e84-42c7-9548-48c254f14c19',
'Content-Type': 'application/json',
'Accept': 'application/json',
}
lexdata = {
"renderType" : "pdf"
}
json_data = json.dumps(lexdata)
r = requests.get("https://api.lexoffice.io/v1/invoices/"+AgencyBills.objects.get(pk=pk).lexid+"/document", data=json_data, headers=headers)
json.loads(r.text)
base64String = requests.get("https://api.lexoffice.io/v1/files/"+json.loads(r.text)["documentFileId"]+"/", data=json_data, headers=headers)
buffer = BytesIO.BytesIO()
content = base64.b64decode(base64String.text)
buffer.write(content)
response = HttpResponse(buffer.getvalue(),content_type="application/pdf")
response['Content-Disposition'] = 'inline;filename=some_file.pdf'
return response
''' '''
AGENCY AGENCY
@ -1532,9 +1587,12 @@ class BillPlanUpdate(UpdateView):
end_date = month + relativedelta(months=plan) end_date = month + relativedelta(months=plan)
end_date_string= end_date.strftime("%d.%m.%Y") end_date_string= end_date.strftime("%d.%m.%Y")
voucher_date_today = date.today().strftime("%Y-%m-%d")
# TODO: Nachgebuchte Mitarbeiter # TODO: Nachgebuchte Mitarbeiter
# TODO: Was passiert bei Änderungen der Agenturdaten? # TODO: Was passiert bei Änderungen der Agenturdaten?
# TODO: Kündigungsmöglichkeit, den Zahlplan zu beenden # TODO: Kündigungsmöglichkeit, den Zahlplan zu beenden
# TODO: voucherDate muss HEUTE sein, Leistungszeitraum aber das von der Agenturregistrierung
# DataJSON # DataJSON
''' '''
@ -1545,9 +1603,8 @@ class BillPlanUpdate(UpdateView):
if form.cleaned_data['paymentplan'] == "1": if form.cleaned_data['paymentplan'] == "1":
monthword = "Monat" monthword = "Monat"
lexdata = { lexdata = {
"voucherDate": voucher_date + "T00:00:00.000+00:00", "voucherDate": voucher_date_today + "T00:00:00.000+00:00",
"address" : { "address" : {
"name" : agency.name, "name" : agency.name,
"street": agency.street, "street": agency.street,
@ -1563,7 +1620,7 @@ class BillPlanUpdate(UpdateView):
"type" : "custom", "type" : "custom",
"name" : "Digitale Agentur: Grundbetrag für " + str(plan) + " " + monthword, "name" : "Digitale Agentur: Grundbetrag für " + str(plan) + " " + monthword,
"quantity" : 1, "quantity" : 1,
"unitName" : "Anzahl", "unitName" : "Stück",
"description" : "Zeitraum " + start_date_string + " - " + end_date_string, "description" : "Zeitraum " + start_date_string + " - " + end_date_string,
"unitPrice" : "unitPrice" :
{ {
@ -1577,7 +1634,7 @@ class BillPlanUpdate(UpdateView):
"name" : "Digitale Agentur: Zusätzliche Mitarbeiter", "name" : "Digitale Agentur: Zusätzliche Mitarbeiter",
"description" : "Zeitraum " + start_date_string + " - " + end_date_string, "description" : "Zeitraum " + start_date_string + " - " + end_date_string,
"quantity" : usercount, "quantity" : usercount,
"unitName" : "Anzahl", "unitName" : "Stück",
"unitPrice" : "unitPrice" :
{ {
"currency" : "EUR", "currency" : "EUR",
@ -1594,15 +1651,15 @@ class BillPlanUpdate(UpdateView):
"paymentTermDuration": 14, "paymentTermDuration": 14,
}, },
"shippingConditions": { "shippingConditions": {
"shippingDate": voucher_date + "T00:00:00.000+00:00", #"shippingDate": voucher_date_today + "T00:00:00.000+00:00",
"shippingType": "service" "shippingType": "none"
}, }
} }
json_data = json.dumps(lexdata) json_data = json.dumps(lexdata)
self.object = form.save(commit=False) self.object = form.save(commit=False)
r = requests.post("https://api.lexoffice.io/v1/invoices", data=json_data, headers=headers) r = requests.post("https://api.lexoffice.io/v1/invoices/?finalize=true", data=json_data, headers=headers)
if(r.status_code == 201): if(r.status_code == 201):
messages.success(self.request, f"Rechnung erstellt!") messages.success(self.request, f"Rechnung erstellt!")
@ -1628,11 +1685,8 @@ class BillPlanUpdate(UpdateView):
if len(agency.lexofficeid) == 0: if len(agency.lexofficeid) == 0:
self.object.lexofficeid = response_text["organizationId"] 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"])
newbill.save() newbill.save()
self.object.save() self.object.save()
else: else:

1
test.pdf Normal file

File diff suppressed because one or more lines are too long

View File

@ -153,7 +153,10 @@ class AgencyBills(models.Model):
billtype = models.CharField(default="", max_length=200) billtype = models.CharField(default="", max_length=200)
billdate = models.DateField(default=timezone.now) billdate = models.DateField(default=timezone.now)
billnumber = models.CharField(default="", max_length=200) billnumber = models.CharField(default="", max_length=200)
# TODO: Rechnungsstatus dazu ob offen oder nicht billstatus = models.CharField(default="", max_length=200, null=True, blank=True)
start = models.DateField(default=timezone.now)
end = models.DateField(default=timezone.now)
plan = models.CharField(default="", max_length=20)
def __str__(self): def __str__(self):
return f'{self.lexid}' return f'{self.lexid}'