Refs #131 -- Basic implementation of invoicing

This commit is contained in:
Raphael Michel
2016-03-12 12:03:00 +01:00
parent 0f054416fc
commit 5ab78b4576
21 changed files with 1489 additions and 374 deletions

View File

@@ -1,6 +1,7 @@
from .auth import User
from .base import CachedFile, cachedfile_name
from .event import Event, EventLock, EventPermission, EventSetting
from .invoices import Invoice, InvoiceLine, invoice_filename
from .items import (
Item, ItemCategory, ItemVariation, Question, Quota, itempicture_upload_to,
)
@@ -17,5 +18,6 @@ __all__ = [
'ItemCategory', 'Item', 'Property', 'PropertyValue', 'ItemVariation', 'VariationsField', 'Question',
'BaseRestriction', 'Quota', 'Order', 'CachedTicket', 'QuestionAnswer', 'AbstractPosition', 'OrderPosition',
'CartPosition', 'EventSetting', 'OrganizerSetting', 'EventLock', 'cachedfile_name', 'itempicture_upload_to',
'generate_secret', 'Voucher', 'LogEntry', 'InvoiceAddress', 'generate_position_secret'
'generate_secret', 'Voucher', 'LogEntry', 'InvoiceAddress', 'generate_position_secret', 'InvoiceLine',
'Invoice', 'invoice_filename'
]

View File

@@ -0,0 +1,62 @@
import random
import string
from datetime import date
from decimal import Decimal
from django.db import DatabaseError, models
from django.db.models import Max
def invoice_filename(instance, filename: str) -> str:
secret = ''.join(random.choice(string.ascii_letters + string.digits) for _ in range(14))
return 'invoices/{org}/{ev}/{ev}-{no}-{code}-{secret}.pdf'.format(
org=instance.event.organizer.slug, ev=instance.event.slug,
no=instance.invoice_no, code=instance.order.code,
secret=secret
)
class Invoice(models.Model):
order = models.ForeignKey('Order', related_name='invoices', db_index=True)
event = models.ForeignKey('Event', related_name='invoices', db_index=True)
invoice_no = models.PositiveIntegerField(db_index=True)
is_cancellation = models.BooleanField(default=False)
refers = models.ForeignKey('Invoice', related_name='refered', null=True, blank=True)
invoice_from = models.TextField()
invoice_to = models.TextField()
date = models.DateField(default=date.today)
locale = models.CharField(max_length=50, default='en')
additional_text = models.TextField(blank=True)
file = models.FileField(null=True, blank=True, upload_to=invoice_filename)
def save(self, *args, **kwargs):
if not self.order:
raise ValueError('Any invoice needs to be connected to an order')
if not self.event:
self.event = self.order.event
if not self.invoice_no:
for i in range(10):
self.invoice_no = (Invoice.objects.filter(
event=self.event).aggregate(m=Max('invoice_no'))['m'] or 0) + 1
try:
return super().save(*args, **kwargs)
except DatabaseError:
# Suppress duplicate key errors and try again
if i == 9:
raise
return super().save(*args, **kwargs)
@property
def number(self):
return '%s-%05d' % (self.event.slug.upper(), self.invoice_no)
class Meta:
unique_together = ('event', 'invoice_no')
class InvoiceLine(models.Model):
invoice = models.ForeignKey('Invoice', related_name='lines')
description = models.TextField()
gross_value = models.DecimalField(max_digits=10, decimal_places=2)
tax_value = models.DecimalField(max_digits=10, decimal_places=2, default=Decimal('0.00'))
tax_rate = models.DecimalField(max_digits=7, decimal_places=2, default=Decimal('0.00'))