1
0
mirror of https://gitlab.crans.org/bde/nk20 synced 2025-06-20 17:41:55 +02:00

Billing -> Invoice

This commit is contained in:
Yohann D'ANELLO
2020-03-22 01:22:27 +01:00
parent 18f6daf2ac
commit 4f343fc99f
12 changed files with 333 additions and 251 deletions

View File

@ -3,11 +3,11 @@
from django.contrib import admin
from .models import Billing, Product
from .models import Invoice, Product
@admin.register(Billing)
class BillingAdmin(admin.ModelAdmin):
@admin.register(Invoice)
class InvoiceAdmin(admin.ModelAdmin):
list_display = ('id', 'name', 'subject', 'acquitted', )

View File

@ -4,17 +4,17 @@
from crispy_forms.helper import FormHelper
from django import forms
from .models import Billing, Product
from .models import Invoice, Product
class BillingForm(forms.ModelForm):
class InvoiceForm(forms.ModelForm):
class Meta:
model = Billing
model = Invoice
fields = '__all__'
ProductFormSet = forms.inlineformset_factory(
Billing,
Invoice,
Product,
fields='__all__',
extra=1,

View File

@ -5,10 +5,10 @@ from django.db import models
from django.utils.translation import gettext_lazy as _
class Billing(models.Model):
class Invoice(models.Model):
id = models.PositiveIntegerField(
primary_key=True,
verbose_name=_("Billing identifier"),
verbose_name=_("Invoice identifier"),
)
bde = models.CharField(
@ -104,8 +104,8 @@ class Billing(models.Model):
class Product(models.Model):
billing = models.ForeignKey(
Billing,
invoice = models.ForeignKey(
Invoice,
on_delete=models.PROTECT,
)

View File

@ -5,16 +5,16 @@ import django_tables2 as tables
from django.utils.translation import gettext_lazy as _
from django_tables2 import A
from .models import Billing
from .models import Invoice
class BillingTable(tables.Table):
id = tables.LinkColumn("treasury:billing_update",
class InvoiceTable(tables.Table):
id = tables.LinkColumn("treasury:invoice_update",
args=[A("pk")],
text=lambda record: _("Billing #{:d}").format(record.id), )
text=lambda record: _("Invoice #{:d}").format(record.id), )
billing = tables.LinkColumn("treasury:billing_render",
verbose_name=_("Billing"),
invoice = tables.LinkColumn("treasury:invoice_render",
verbose_name=_("Invoice"),
args=[A("pk")],
accessor="pk",
text="",
@ -27,6 +27,6 @@ class BillingTable(tables.Table):
attrs = {
'class': 'table table-condensed table-striped table-hover'
}
model = Billing
model = Invoice
template_name = 'django_tables2/bootstrap4.html'
fields = ('id', 'name', 'subject', 'acquitted', 'billing',)
fields = ('id', 'name', 'subject', 'acquitted', 'invoice',)

View File

@ -3,12 +3,12 @@
from django.urls import path
from .views import BillingCreateView, BillingListView, BillingUpdateView, BillingRenderView
from .views import InvoiceCreateView, InvoiceListView, InvoiceUpdateView, InvoiceRenderView
app_name = 'treasury'
urlpatterns = [
path('billing/', BillingListView.as_view(), name='billing'),
path('billing/create/', BillingCreateView.as_view(), name='billing_create'),
path('billing/<int:pk>/', BillingUpdateView.as_view(), name='billing_update'),
path('billing/render/<int:pk>/', BillingRenderView.as_view(), name='billing_render'),
path('invoice/', InvoiceListView.as_view(), name='invoice'),
path('invoice/create/', InvoiceCreateView.as_view(), name='invoice_create'),
path('invoice/<int:pk>/', InvoiceUpdateView.as_view(), name='invoice_update'),
path('invoice/render/<int:pk>/', InvoiceRenderView.as_view(), name='invoice_render'),
]

View File

@ -17,17 +17,17 @@ from django.views.generic.base import View
from django_tables2 import SingleTableView
from note_kfet.settings.base import BASE_DIR
from .forms import BillingForm, ProductFormSet, ProductFormSetHelper
from .models import Billing, Product
from .tables import BillingTable
from .forms import InvoiceForm, ProductFormSet, ProductFormSetHelper
from .models import Invoice, Product
from .tables import InvoiceTable
class BillingCreateView(LoginRequiredMixin, CreateView):
class InvoiceCreateView(LoginRequiredMixin, CreateView):
"""
Create Billing
Create Invoice
"""
model = Billing
form_class = BillingForm
model = Invoice
form_class = InvoiceForm
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
@ -64,23 +64,23 @@ class BillingCreateView(LoginRequiredMixin, CreateView):
return ret
def get_success_url(self):
return reverse_lazy('treasury:billing')
return reverse_lazy('treasury:invoice')
class BillingListView(LoginRequiredMixin, SingleTableView):
class InvoiceListView(LoginRequiredMixin, SingleTableView):
"""
List existing Billings
List existing Invoices
"""
model = Billing
table_class = BillingTable
model = Invoice
table_class = InvoiceTable
class BillingUpdateView(LoginRequiredMixin, UpdateView):
class InvoiceUpdateView(LoginRequiredMixin, UpdateView):
"""
Create Billing
Create Invoice
"""
model = Billing
form_class = BillingForm
model = Invoice
form_class = InvoiceForm
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
@ -119,27 +119,27 @@ class BillingUpdateView(LoginRequiredMixin, UpdateView):
else:
f.instance = None
Product.objects.filter(~Q(pk__in=saved), billing=form.instance).delete()
Product.objects.filter(~Q(pk__in=saved), invoice=form.instance).delete()
return ret
def get_success_url(self):
return reverse_lazy('treasury:billing')
return reverse_lazy('treasury:invoice')
class BillingRenderView(LoginRequiredMixin, View):
class InvoiceRenderView(LoginRequiredMixin, View):
"""
Render Billing as generated PDF
Render Invoice as generated PDF
"""
def get(self, request, **kwargs):
pk = kwargs["pk"]
billing = Billing.objects.get(pk=pk)
products = Product.objects.filter(billing=billing).all()
invoice = Invoice.objects.get(pk=pk)
products = Product.objects.filter(invoice=invoice).all()
billing.description = billing.description.replace("\n", "\\newline\n")
billing.address = billing.address.replace("\n", "\\newline\n")
tex = render_to_string("treasury/billing_sample.tex", dict(obj=billing, products=products))
invoice.description = invoice.description.replace("\n", "\\newline\n")
invoice.address = invoice.address.replace("\n", "\\newline\n")
tex = render_to_string("treasury/invoice_sample.tex", dict(obj=invoice, products=products))
try:
os.mkdir(BASE_DIR + "/tmp")
except FileExistsError:
@ -147,13 +147,13 @@ class BillingRenderView(LoginRequiredMixin, View):
tmp_dir = mkdtemp(prefix=BASE_DIR + "/tmp/")
try:
with open("{}/billing-{:d}.tex".format(tmp_dir, pk), "wb") as f:
with open("{}/invoice-{:d}.tex".format(tmp_dir, pk), "wb") as f:
f.write(tex.encode("UTF-8"))
del tex
for _ in range(2):
error = subprocess.Popen(
["pdflatex", "billing-{}.tex".format(pk)],
["pdflatex", "invoice-{}.tex".format(pk)],
cwd=tmp_dir,
stdin=open(os.devnull, "r"),
stderr=open(os.devnull, "wb"),
@ -161,11 +161,11 @@ class BillingRenderView(LoginRequiredMixin, View):
).wait()
if error:
raise IOError("An error attempted while generating a billing (code=" + str(error) + ")")
raise IOError("An error attempted while generating a invoice (code=" + str(error) + ")")
pdf = open("{}/billing-{}.pdf".format(tmp_dir, pk), 'rb').read()
pdf = open("{}/invoice-{}.pdf".format(tmp_dir, pk), 'rb').read()
response = HttpResponse(pdf, content_type="application/pdf")
response['Content-Disposition'] = "inline;filename=billing-{:d}.pdf".format(pk)
response['Content-Disposition'] = "inline;filename=invoice-{:d}.pdf".format(pk)
except IOError as e:
raise e
finally: