Skip to content
Snippets Groups Projects
Commit fc51172b authored by Nik | Klampfradler's avatar Nik | Klampfradler
Browse files

Merge branch '2-add-manual-invoicing' into 'master'

Add models for manual invoicing

See merge request !10
parents 58c824ec f24130d1
No related branches found
No related tags found
1 merge request!10Add models for manual invoicing
Pipeline #59542 failed
# Generated by Django 3.2.12 on 2022-03-12 21:41
import django.contrib.sites.managers
from django.db import migrations, models
import django.db.models.deletion
class Migration(migrations.Migration):
dependencies = [
('core', '0038_notification_send_at.py'),
('sites', '0002_alter_domain_unique'),
('tezor', '0002_invoice_due_date'),
]
operations = [
migrations.CreateModel(
name='InvoiceItem',
fields=[
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('extended_data', models.JSONField(default=dict, editable=False)),
('sku', models.CharField(blank=True, max_length=255, verbose_name='Article no.')),
('description', models.CharField(max_length=255, verbose_name='Purchased item')),
('price', models.DecimalField(decimal_places=2, default='0.0', max_digits=9, verbose_name='Item gross price')),
('currency', models.CharField(max_length=10, verbose_name='Currency')),
('tax_rate', models.DecimalField(decimal_places=1, default='0.0', max_digits=4, verbose_name='Tax rate')),
],
options={
'abstract': False,
},
managers=[
('objects', django.contrib.sites.managers.CurrentSiteManager()),
],
),
migrations.AddField(
model_name='invoice',
name='person',
field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, to='core.person', verbose_name='Invoice recipient (person)'),
),
migrations.AddConstraint(
model_name='invoice',
constraint=models.CheckConstraint(check=models.Q(('for_object_id__isnull', True), ('person__isnull', True), _connector='OR'), name='object_or_person'),
),
migrations.AddField(
model_name='invoiceitem',
name='site',
field=models.ForeignKey(default=1, editable=False, on_delete=django.db.models.deletion.CASCADE, to='sites.site'),
),
migrations.AddField(
model_name='invoice',
name='items',
field=models.ManyToManyField(to='tezor.InvoiceItem', verbose_name='Invoice items'),
),
]
...@@ -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)
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment