116 lines
3.3 KiB
Python
116 lines
3.3 KiB
Python
|
from django.db import models
|
||
|
from django.contrib.auth import get_user_model
|
||
|
from django.core.files.base import ContentFile
|
||
|
from django.utils import timezone
|
||
|
|
||
|
import uuid
|
||
|
|
||
|
from dbsettings.functions import getValue
|
||
|
|
||
|
from auction.models import Inquiry
|
||
|
|
||
|
from .billingaddress import BillingAddress
|
||
|
|
||
|
from ..functions import invoice_upload_path
|
||
|
from ..pdfviews import InvoicePDFView
|
||
|
|
||
|
class InvoiceTypeChoices(models.IntegerChoices):
|
||
|
INVOICE = (0, "Rechnung")
|
||
|
DEPOSIT = (1, "Sicherheitsleistung")
|
||
|
|
||
|
class Invoice(models.Model):
|
||
|
uuid = models.UUIDField(default=uuid.uuid4)
|
||
|
user = models.ForeignKey(get_user_model(), models.PROTECT)
|
||
|
billing_address = models.ForeignKey(BillingAddress, models.PROTECT)
|
||
|
currency = models.CharField(max_length=3)
|
||
|
tax_rate = models.DecimalField(max_digits=4, decimal_places=2)
|
||
|
invoice = models.FileField(null=True, blank=True, upload_to=invoice_upload_path)
|
||
|
inquiry = models.OneToOneField(Inquiry, null=True, blank=True, on_delete=models.SET_NULL)
|
||
|
created = models.DateTimeField(auto_now_add=True)
|
||
|
type = models.IntegerField(choices=InvoiceTypeChoices.choices)
|
||
|
|
||
|
@property
|
||
|
def price_net(self):
|
||
|
price = 0
|
||
|
|
||
|
for item in self.invoiceitem_set.all():
|
||
|
price += item.net_total
|
||
|
|
||
|
return price
|
||
|
|
||
|
@property
|
||
|
def tax(self):
|
||
|
return round(self.price_net * self.tax_rate / 100, 2)
|
||
|
|
||
|
@property
|
||
|
def price_gross(self):
|
||
|
return self.price_net + self.tax
|
||
|
|
||
|
@property
|
||
|
def payment_instructions(self):
|
||
|
return None
|
||
|
|
||
|
@property
|
||
|
def url(self):
|
||
|
try:
|
||
|
return self.invoice.url
|
||
|
except:
|
||
|
return False
|
||
|
|
||
|
@property
|
||
|
def balance(self):
|
||
|
paid_amount = 0
|
||
|
|
||
|
for payment in self.invoicepayment_set.all():
|
||
|
paid_amount += payment.amount
|
||
|
|
||
|
return paid_amount - self.price_gross
|
||
|
|
||
|
@property
|
||
|
def is_paid(self):
|
||
|
return self.balance >= 0
|
||
|
|
||
|
def finalize(self, *args, **kwargs):
|
||
|
if self.is_paid:
|
||
|
try:
|
||
|
self.inquiry.process_payment(*args, **kwargs)
|
||
|
except Inquiry.DoesNotExist:
|
||
|
pass
|
||
|
|
||
|
self.generate_invoice()
|
||
|
|
||
|
def generate_invoice(self):
|
||
|
view = InvoicePDFView()
|
||
|
|
||
|
bottom_tip = (f"{ self.payment_instructions }<br /><br />" if self.payment_instructions else "") + getValue("billing.bottom_tip", "")
|
||
|
bottom_tip += "<br />" if bottom_tip else ""
|
||
|
bottom_tip += "Dokument erstellt: %s" % str(timezone.now())
|
||
|
|
||
|
args = {
|
||
|
"type": InvoiceTypeChoices._value2label_map_[self.type],
|
||
|
"object": self,
|
||
|
"bottom_tip": bottom_tip
|
||
|
}
|
||
|
|
||
|
self.invoice = ContentFile(view.render(**args), "invoice.pdf")
|
||
|
self.save()
|
||
|
|
||
|
@classmethod
|
||
|
def from_inquiry(cls, inquiry):
|
||
|
invoice = cls.objects.create(
|
||
|
user = inquiry.client.user,
|
||
|
billing_address = BillingAddress.from_profile(inquiry.client),
|
||
|
currency = settings.CURRENCY_CODE,
|
||
|
tax_rate = 0,
|
||
|
inquiry = inquiry
|
||
|
)
|
||
|
|
||
|
InvoiceItem.objects.create(
|
||
|
invoice = invoice,
|
||
|
name = "SL",
|
||
|
description = "Rückzahlbare Sicherheitsleistung zu JourneyJoker-Anfrage #%i" % inquiry.id,
|
||
|
count = 1,
|
||
|
net_each = inquiry.budget
|
||
|
)
|
||
|
|
||
|
return invoice
|