Skip to content
Snippets Groups Projects

Add models for manual invoicing

Merged Nik | Klampfradler requested to merge 2-add-manual-invoicing into master
2 files
+ 14
12
Compare changes
  • Side-by-side
  • Inline
Files
2
@@ -2,17 +2,18 @@ from django.conf import settings
@@ -2,17 +2,18 @@ from django.conf import settings
from django.contrib.contenttypes.fields import GenericForeignKey
from django.contrib.contenttypes.fields import GenericForeignKey
from django.contrib.contenttypes.models import ContentType
from django.contrib.contenttypes.models import ContentType
from django.db import models
from django.db import models
 
from django.db.models import Q
from django.shortcuts import reverse
from django.shortcuts import reverse
from django.utils.translation import gettext_lazy as _
from django.utils.translation import gettext_lazy as _
from djmoney.models.fields import CurrencyField, MoneyField
from payments import PaymentStatus, PurchasedItem
from payments import PaymentStatus, PurchasedItem
from payments.models import BasePayment
from payments.models import BasePayment
from aleksis.core.mixins import ExtensibleModel, PureDjangoModel
from aleksis.core.mixins import ExtensibleModel, PureDjangoModel
 
from aleksis.core.models import Person
from .base import Client
from ..tables import PurchasedItemsTable, TotalsTable
from ..tables import PurchasedItemsTable, TotalsTable
 
from .base import Client
class InvoiceGroup(ExtensibleModel):
class InvoiceGroup(ExtensibleModel):
@@ -61,6 +62,10 @@ class Invoice(BasePayment, PureDjangoModel):
@@ -61,6 +62,10 @@ class Invoice(BasePayment, PureDjangoModel):
for_object_id = models.PositiveIntegerField()
for_object_id = models.PositiveIntegerField()
for_object = GenericForeignKey("for_content_type", "for_object_id")
for_object = GenericForeignKey("for_content_type", "for_object_id")
 
# For manual invoicing
 
person = models.ForeignKey(Person, on_delete=models.SET_NULL, verbose_name=_("Invoice recipient (person)"), blank=True, null=True)
 
items = models.ManyToManyField("InvoiceItem", verbose_name=_("Invoice items"))
 
@classmethod
@classmethod
def get_variant_choices(cls):
def get_variant_choices(cls):
choices = []
choices = []
@@ -78,10 +83,15 @@ class Invoice(BasePayment, PureDjangoModel):
@@ -78,10 +83,15 @@ class Invoice(BasePayment, PureDjangoModel):
return self.__class__.STATUS_ICONS[self.status]
return self.__class__.STATUS_ICONS[self.status]
def get_purchased_items(self):
def get_purchased_items(self):
return self.for_object.get_purchased_items()
for item in self.items.all():
 
yield item.as_purchased_item()
 
else:
 
return self.for_object.get_purchased_items()
def get_person(self):
def get_person(self):
if hasattr(self.for_object, "person"):
if self.person:
 
return self.person
 
elif hasattr(self.for_object, "person"):
return self.for_object.person
return self.for_object.person
elif hasattr(self.for_object, "get_person"):
elif hasattr(self.for_object, "get_person"):
return self.for_object.get_person()
return self.for_object.get_person()
@@ -90,7 +100,8 @@ class Invoice(BasePayment, PureDjangoModel):
@@ -90,7 +100,8 @@ class Invoice(BasePayment, PureDjangoModel):
class Meta:
class Meta:
constraints = [
constraints = [
models.UniqueConstraint(fields=["number", "group"], name="number_uniq_per_group")
models.UniqueConstraint(fields=["number", "group"], name="number_uniq_per_group"),
 
models.CheckConstraint(check=(Q(for_object_id__isnull=True) | Q(person__isnull=True)), name="object_or_person"),
]
]
@property
@property
@@ -126,3 +137,14 @@ class Invoice(BasePayment, PureDjangoModel):
@@ -126,3 +137,14 @@ class Invoice(BasePayment, PureDjangoModel):
def get_failure_url(self):
def get_failure_url(self):
return reverse("invoice_by_token", kwargs={"slug": self.token})
return reverse("invoice_by_token", kwargs={"slug": self.token})
 
 
 
class InvoiceItem(ExtensibleModel):
 
sku = models.CharField(max_length=255, verbose_name=_("Article no."), blank=True)
 
description = models.CharField(max_length=255, verbose_name=_("Purchased item"))
 
price = models.DecimalField(verbose_name=_("Item gross price"), max_digits=9, decimal_places=2, default="0.0")
 
currency = models.CharField(max_length=10, verbose_name=_("Currency"))
 
tax_rate = models.DecimalField(verbose_name=_("Tax rate"), max_digits=4, decimal_places=1, default="0.0")
 
 
def as_purchased_item(self):
 
yield PurchasedItem(name=self.description, quantity=1, price=self.price, currency=self.currency, sku=self.sku, tax_rate=self.tax_rate)
Loading