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 from dateutil.relativedelta import relativedelta from pyinvoice.models import InvoiceInfo, ServiceProviderInfo, ClientInfo, Item, Transaction, PDFInfo from pyinvoice.templates import SimpleInvoice from polymorphic.models import PolymorphicModel from django_countries.fields import CountryField from io import BytesIO import urllib.request from dbsettings.functions import getValue from .functions import invoice_upload_path from auction.models import Inquiry class BillingAddress(models.Model): user = models.ForeignKey(get_user_model(), models.CASCADE) company = models.CharField(max_length=64, null=True, blank=True) vat_id = models.CharField(max_length=32, null=True, blank=True) first_name = models.CharField(max_length=64) last_name = models.CharField(max_length=64) street = models.CharField(max_length=128) city = models.CharField(max_length=64) zip = models.CharField(max_length=16) state = models.CharField(max_length=32, null=True, blank=True) country = CountryField() class Invoice(models.Model): 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) @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 "Alle Preise in %s." % self.currency @property def url(self): return False @property def is_paid(self): paid_amount = 0 for payment in self.invoicepayment_set().all(): paid_amount += payment.amount if paid_amount >= price_gross: return True return False def generate_invoice(self): output = BytesIO() pdfinfo = PDFInfo(title='Rechnung', author='Kumi Media Ltd.', subject='Rechnung') doc = SimpleInvoice(output, pdfinfo) doc.is_paid = self.is_paid doc.invoice_info = InvoiceInfo("%s%i" % (getValue("billing.prefix", ""), self.id), timezone.now().date(), timezone.now().date()) provider_data = { key: value for key, value in { "name": getValue("billing.provider.name", False), "street": getValue("billing.provider.street", False), "city": getValue("billing.provider.city", False), "state": getValue("billing.provider.state", False), "country": getValue("billing.provider.country", False), "post_code": getValue("billing.provider.zip", False), "vat_tax_number": getValue("billing.provider.vat_id", False) }.items() if value} doc.service_provider_info = ServiceProviderInfo(**provider_data) logo_url = getValue("billing.logo_url", False) if logo_url: try: logo = BytesIO(urllib.request.urlopen(logo_url).read()) doc.logo(logo) except: pass profile = self.user.clientprofile if self.inquiry else self.user.partnerprofile client_data = { key: value for key, value in { "name": profile.full_name, "street": profile.street, "city": profile.city, "state": profile.state, "country": profile.country, "post_code": profile.zip, "vat_tax_number": profile.vat_id, "email": self.user.email, }.items() if value} doc.client_info = ClientInfo(**client_data) for item in self.invoiceitem_set().all(): doc.add_item(Item(item.name, item.description, item.count, item.net_each)) doc.set_item_tax_rate(self.tax_rate) for payment in self.invoicepayment_set().all(): doc.add_transaction(Transaction(payment.gateway, payment.gateway_id, payment.timestamp, payment.amount)) bottom_tip = (f"{ self.payment_instructions }

" if self.payment_instructions else "") + getValue("billing.bottom_tip", "") bottom_tip += "

" if bottom_tip else "" bottom_tip += "Rechnung erstellt: %s" % str(timezone.now()) doc.set_bottom_tip(bottom_tip) doc.finish() self.invoice = ContentFile(output.getvalue(), "invoice.pdf") self.save() class InvoiceItem(models.Model): invoice = models.ForeignKey(Invoice, models.CASCADE) name = models.CharField(max_length=64) description = models.CharField(max_length=256, null=True, blank=True) count = models.IntegerField() net_each = models.DecimalField(max_digits=11, decimal_places=2) class InvoicePayment(PolymorphicModel): invoice = models.ForeignKey(Invoice, models.PROTECT) amount = models.DecimalField(max_digits=9, decimal_places=2) gateway_id = models.CharField(max_length=256) timestamp = models.DateTimeField(default=timezone.now) @property def gateway(self): raise NotImplementedError("%s does not implement gateway" % type(self)) @classmethod def initiate(cls, invoice): raise NotImplementedError("%s does not implement initiate()" % cls.__name__)