from django.contrib.contenttypes.fields import GenericForeignKey from django.contrib.contenttypes.models import ContentType from django.db import models from django.utils.translation import gettext_lazy as _ from djmoney.models.fields import CurrencyField, MoneyField from payments import PurchasedItem from payments.models import BasePayment from aleksis.core.mixins import ExtensibleModel, PureDjangoModel from .base import Client from ..tables import PurchasedItemsTable, TotalsTable class InvoiceGroup(ExtensibleModel): name = models.CharField(verbose_name=_("Invoice group name"), max_length=255) client = models.ForeignKey( Client, verbose_name=_("Linked client"), related_name="invoice_groups", on_delete=models.SET_NULL, null=True ) template_name = models.CharField(verbose_name=_("Template to render invoices with as PDF"), blank=True, max_length=255) def __str__(self) -> str: return self.name class Meta: constraints = [ models.UniqueConstraint(fields=["client", "name"], name="group_uniq_per_client") ] class Invoice(BasePayment, PureDjangoModel): group = models.ForeignKey( InvoiceGroup, verbose_name=_("Invoice group"), related_name="invoices", on_delete=models.SET_NULL, null=True ) number = models.CharField(verbose_name=_("Invoice number"), max_length=255) for_content_type = models.ForeignKey(ContentType, on_delete=models.SET_NULL, null=True) for_object_id = models.PositiveIntegerField() for_object = GenericForeignKey("for_content_type", "for_object_id") def get_purchased_items(self): return self.for_object.get_purchased_items() class Meta: constraints = [ models.UniqueConstraint(fields=["transaction_id", "group"], name="number_uniq_per_group") ] @property def purchased_items_table(self): items = [i._asdict() for i in self.get_purchased_items()] return PurchasedItemsTable(items) @property def totals_table(self): tax_amounts = {} for item in self.get_purchased_items(): tax_amounts.setdefault(item.tax_rate, 0) tax_amounts[item.tax_rate] += item.price / (item.tax_rate + 100) * item.tax_rate values = [] for tax_rate, total in tax_amounts.items(): values.append({ "name": _("Included VAT {} %").format(tax_rate), "value": total, "currency": self.currency, }) values.append({ "name": _("Gross total"), "value": self.total, "currency": self.currency, }) return TotalsTable(values)