forked from CGM_Public/pretix_original
Add quota and order models
This commit is contained in:
125
src/tixlbase/migrations/0017_auto_20141017_2148.py
Normal file
125
src/tixlbase/migrations/0017_auto_20141017_2148.py
Normal file
@@ -0,0 +1,125 @@
|
|||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
from __future__ import unicode_literals
|
||||||
|
|
||||||
|
from django.db import models, migrations
|
||||||
|
import tixlbase.models
|
||||||
|
from django.conf import settings
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('tixlbase', '0016_event_plugins'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.CreateModel(
|
||||||
|
name='CartPosition',
|
||||||
|
fields=[
|
||||||
|
('id', models.AutoField(primary_key=True, serialize=False, verbose_name='ID', auto_created=True)),
|
||||||
|
('session', models.CharField(null=True, max_length=255, blank=True, verbose_name='Session key')),
|
||||||
|
('total', models.DecimalField(max_digits=10, verbose_name='Price', decimal_places=2)),
|
||||||
|
('datetime', models.DateTimeField(verbose_name='Datetime')),
|
||||||
|
('expires', models.DateTimeField(verbose_name='Expiration date')),
|
||||||
|
('event', models.ForeignKey(to='tixlbase.Event', verbose_name='Event')),
|
||||||
|
('item', models.ForeignKey(to='tixlbase.Item', verbose_name='Item')),
|
||||||
|
('user', models.ForeignKey(null=True, blank=True, to=settings.AUTH_USER_MODEL, verbose_name='User')),
|
||||||
|
('variation', models.ForeignKey(null=True, blank=True, to='tixlbase.ItemVariation', verbose_name='Variation')),
|
||||||
|
],
|
||||||
|
options={
|
||||||
|
'verbose_name_plural': 'Cart positions',
|
||||||
|
'verbose_name': 'Cart position',
|
||||||
|
},
|
||||||
|
bases=(models.Model,),
|
||||||
|
),
|
||||||
|
migrations.CreateModel(
|
||||||
|
name='Order',
|
||||||
|
fields=[
|
||||||
|
('id', models.AutoField(primary_key=True, serialize=False, verbose_name='ID', auto_created=True)),
|
||||||
|
('status', models.CharField(max_length=3, choices=[('p', 'pending'), ('n', 'paid'), ('e', 'expired'), ('c', 'cancelled')], verbose_name='Status')),
|
||||||
|
('datetime', models.DateTimeField(auto_now_add=True, verbose_name='Date')),
|
||||||
|
('expires', models.DateTimeField(verbose_name='Expiration date')),
|
||||||
|
('payment_date', models.DateTimeField(verbose_name='Payment date')),
|
||||||
|
('payment_info', models.TextField(verbose_name='Payment information')),
|
||||||
|
('total', models.DecimalField(max_digits=10, verbose_name='Total amount', decimal_places=2)),
|
||||||
|
('event', models.ForeignKey(to='tixlbase.Event', verbose_name='Event')),
|
||||||
|
('user', models.ForeignKey(null=True, blank=True, to=settings.AUTH_USER_MODEL, verbose_name='User')),
|
||||||
|
],
|
||||||
|
options={
|
||||||
|
'verbose_name_plural': 'Orders',
|
||||||
|
'verbose_name': 'Order',
|
||||||
|
},
|
||||||
|
bases=(models.Model,),
|
||||||
|
),
|
||||||
|
migrations.CreateModel(
|
||||||
|
name='OrderPosition',
|
||||||
|
fields=[
|
||||||
|
('id', models.AutoField(primary_key=True, serialize=False, verbose_name='ID', auto_created=True)),
|
||||||
|
('price', models.DecimalField(max_digits=10, verbose_name='Price', decimal_places=2)),
|
||||||
|
],
|
||||||
|
options={
|
||||||
|
'verbose_name_plural': 'Order positions',
|
||||||
|
'verbose_name': 'Order position',
|
||||||
|
},
|
||||||
|
bases=(models.Model,),
|
||||||
|
),
|
||||||
|
migrations.CreateModel(
|
||||||
|
name='QuestionAnswer',
|
||||||
|
fields=[
|
||||||
|
('id', models.AutoField(primary_key=True, serialize=False, verbose_name='ID', auto_created=True)),
|
||||||
|
('answer', models.TextField()),
|
||||||
|
('cartposition', models.ForeignKey(null=True, blank=True, to='tixlbase.CartPosition')),
|
||||||
|
('orderposition', models.ForeignKey(null=True, blank=True, to='tixlbase.OrderPosition')),
|
||||||
|
('question', models.ForeignKey(to='tixlbase.Question')),
|
||||||
|
],
|
||||||
|
options={
|
||||||
|
},
|
||||||
|
bases=(models.Model,),
|
||||||
|
),
|
||||||
|
migrations.CreateModel(
|
||||||
|
name='Quota',
|
||||||
|
fields=[
|
||||||
|
('id', models.AutoField(primary_key=True, serialize=False, verbose_name='ID', auto_created=True)),
|
||||||
|
('name', models.CharField(max_length=200, verbose_name='Name')),
|
||||||
|
('size', models.PositiveIntegerField(verbose_name='Total capacity')),
|
||||||
|
('items', models.ManyToManyField(to='tixlbase.Item', blank=True, verbose_name='Item')),
|
||||||
|
('lock_cache', models.ManyToManyField(to='tixlbase.CartPosition', blank=True)),
|
||||||
|
('order_cache', models.ManyToManyField(to='tixlbase.OrderPosition', blank=True)),
|
||||||
|
('variations', tixlbase.models.VariationsField(to='tixlbase.ItemVariation', blank=True, verbose_name='Variations')),
|
||||||
|
],
|
||||||
|
options={
|
||||||
|
'verbose_name_plural': 'Quotas',
|
||||||
|
'verbose_name': 'Quota',
|
||||||
|
},
|
||||||
|
bases=(models.Model,),
|
||||||
|
),
|
||||||
|
migrations.AddField(
|
||||||
|
model_name='orderposition',
|
||||||
|
name='answers',
|
||||||
|
field=models.ManyToManyField(to='tixlbase.Question', through='tixlbase.QuestionAnswer', verbose_name='Answers'),
|
||||||
|
preserve_default=True,
|
||||||
|
),
|
||||||
|
migrations.AddField(
|
||||||
|
model_name='orderposition',
|
||||||
|
name='item',
|
||||||
|
field=models.ForeignKey(to='tixlbase.Item', verbose_name='Item'),
|
||||||
|
preserve_default=True,
|
||||||
|
),
|
||||||
|
migrations.AddField(
|
||||||
|
model_name='orderposition',
|
||||||
|
name='order',
|
||||||
|
field=models.ForeignKey(to='tixlbase.Order', verbose_name='Order'),
|
||||||
|
preserve_default=True,
|
||||||
|
),
|
||||||
|
migrations.AddField(
|
||||||
|
model_name='orderposition',
|
||||||
|
name='variation',
|
||||||
|
field=models.ForeignKey(null=True, blank=True, to='tixlbase.ItemVariation', verbose_name='Variation'),
|
||||||
|
preserve_default=True,
|
||||||
|
),
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name='event',
|
||||||
|
name='payment_term_days',
|
||||||
|
field=models.PositiveIntegerField(verbose_name='Payment term in days', default=14, help_text='The number of days after placing an order the user has to pay to preserve his reservation.'),
|
||||||
|
),
|
||||||
|
]
|
||||||
@@ -266,7 +266,7 @@ class Event(models.Model):
|
|||||||
verbose_name=_("Start of presale"),
|
verbose_name=_("Start of presale"),
|
||||||
help_text=_("No items will be sold before this date."),
|
help_text=_("No items will be sold before this date."),
|
||||||
)
|
)
|
||||||
payment_term_days = models.IntegerField(
|
payment_term_days = models.PositiveIntegerField(
|
||||||
default=14,
|
default=14,
|
||||||
verbose_name=_("Payment term in days"),
|
verbose_name=_("Payment term in days"),
|
||||||
help_text=_("The number of days after placing an order the user has to pay to preserve his reservation."),
|
help_text=_("The number of days after placing an order the user has to pay to preserve his reservation."),
|
||||||
@@ -709,13 +709,14 @@ class BaseRestriction(models.Model):
|
|||||||
)
|
)
|
||||||
item = models.ForeignKey(
|
item = models.ForeignKey(
|
||||||
Item,
|
Item,
|
||||||
blank=True,
|
blank=True, null=True,
|
||||||
null=True,
|
verbose_name=_("Item"),
|
||||||
related_name="restrictions_%(app_label)s_%(class)s",
|
related_name="restrictions_%(app_label)s_%(class)s",
|
||||||
)
|
)
|
||||||
variations = VariationsField(
|
variations = VariationsField(
|
||||||
ItemVariation,
|
ItemVariation,
|
||||||
blank=True,
|
blank=True,
|
||||||
|
verbose_name=_("Variations"),
|
||||||
related_name="restrictions_%(app_label)s_%(class)s",
|
related_name="restrictions_%(app_label)s_%(class)s",
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -728,3 +729,203 @@ class BaseRestriction(models.Model):
|
|||||||
if self.event:
|
if self.event:
|
||||||
self.event.get_cache().clear()
|
self.event.get_cache().clear()
|
||||||
return super().save(*args, **kwargs)
|
return super().save(*args, **kwargs)
|
||||||
|
|
||||||
|
|
||||||
|
class Quota(models.Model):
|
||||||
|
"""
|
||||||
|
A quota is a "pool of tickets". It is there to limit the number of items
|
||||||
|
of a certain type to be sold. For example, you could have a quota of 500
|
||||||
|
applied to all your items (because you only have that much space in your
|
||||||
|
building), and also a quota of 100 applied to the VIP tickets for
|
||||||
|
exclusivity. In this case, no more than 500 tickets will be sold in total
|
||||||
|
and no more than 100 of them will be VIP tickets (but 450 normal and 50
|
||||||
|
VIP tickets will be fine).
|
||||||
|
|
||||||
|
As always, a quota can not only be tied to an item, but also to a specific
|
||||||
|
variation. We follow the general rule here: If there are no variations
|
||||||
|
speficied, the quota applies to all of them, and if there are variations
|
||||||
|
specified, the quota applies to those.
|
||||||
|
|
||||||
|
This object holds two fields, "order_cache" and "lock_cache", which are
|
||||||
|
implementation specific and are considered private. It is planned that they
|
||||||
|
are being used as a fallback solution if redis is not available.
|
||||||
|
"""
|
||||||
|
name = models.CharField(
|
||||||
|
max_length=200,
|
||||||
|
verbose_name=_("Name")
|
||||||
|
)
|
||||||
|
size = models.PositiveIntegerField(
|
||||||
|
verbose_name=_("Total capacity")
|
||||||
|
)
|
||||||
|
items = models.ManyToManyField(
|
||||||
|
Item,
|
||||||
|
verbose_name=_("Item"),
|
||||||
|
blank=True
|
||||||
|
)
|
||||||
|
variations = VariationsField(
|
||||||
|
ItemVariation,
|
||||||
|
blank=True,
|
||||||
|
verbose_name=_("Variations")
|
||||||
|
)
|
||||||
|
order_cache = models.ManyToManyField(
|
||||||
|
'OrderPosition',
|
||||||
|
blank=True
|
||||||
|
)
|
||||||
|
lock_cache = models.ManyToManyField(
|
||||||
|
'CartPosition',
|
||||||
|
blank=True
|
||||||
|
)
|
||||||
|
|
||||||
|
class Meta:
|
||||||
|
verbose_name = _("Quota")
|
||||||
|
verbose_name_plural = _("Quotas")
|
||||||
|
|
||||||
|
|
||||||
|
class Order(models.Model):
|
||||||
|
"""
|
||||||
|
An order is created when a user clicks 'buy' on his cart. It holds
|
||||||
|
several OrderPositions and is connected to an user. It has an
|
||||||
|
expiration date: If items run out of capacity, orders which are over
|
||||||
|
their expiration date might be cancelled.
|
||||||
|
|
||||||
|
Important: An order holds its total monetary value, as an order is a
|
||||||
|
piece of 'history' and must not change due to a change in item prices.
|
||||||
|
"""
|
||||||
|
|
||||||
|
STATUS_PENDING = "n"
|
||||||
|
STATUS_PAID = "p"
|
||||||
|
STATUS_EXPIRED = "e"
|
||||||
|
STATUS_CANCELLED = "c"
|
||||||
|
STATUS_CHOICE = (
|
||||||
|
(STATUS_PAID, _("pending")),
|
||||||
|
(STATUS_PENDING, _("paid")),
|
||||||
|
(STATUS_EXPIRED, _("expired")),
|
||||||
|
(STATUS_CANCELLED, _("cancelled")),
|
||||||
|
)
|
||||||
|
|
||||||
|
status = models.CharField(
|
||||||
|
max_length=3,
|
||||||
|
choices=STATUS_CHOICE,
|
||||||
|
verbose_name=_("Status")
|
||||||
|
)
|
||||||
|
event = models.ForeignKey(
|
||||||
|
Event,
|
||||||
|
verbose_name=_("Event")
|
||||||
|
)
|
||||||
|
user = models.ForeignKey(
|
||||||
|
User, null=True, blank=True,
|
||||||
|
verbose_name=_("User")
|
||||||
|
)
|
||||||
|
datetime = models.DateTimeField(
|
||||||
|
auto_now_add=True,
|
||||||
|
verbose_name=_("Date")
|
||||||
|
)
|
||||||
|
expires = models.DateTimeField(
|
||||||
|
verbose_name=_("Expiration date")
|
||||||
|
)
|
||||||
|
payment_date = models.DateTimeField(
|
||||||
|
verbose_name=_("Payment date")
|
||||||
|
)
|
||||||
|
payment_info = models.TextField(
|
||||||
|
verbose_name=_("Payment information")
|
||||||
|
)
|
||||||
|
total = models.DecimalField(
|
||||||
|
decimal_places=2, max_digits=10,
|
||||||
|
verbose_name=_("Total amount")
|
||||||
|
)
|
||||||
|
|
||||||
|
class Meta:
|
||||||
|
verbose_name = _("Order")
|
||||||
|
verbose_name_plural = _("Orders")
|
||||||
|
|
||||||
|
|
||||||
|
class QuestionAnswer(models.Model):
|
||||||
|
"""
|
||||||
|
The answer to a Question, connected to an OrderPosition or CartPosition
|
||||||
|
"""
|
||||||
|
orderposition = models.ForeignKey('OrderPosition', null=True, blank=True)
|
||||||
|
cartposition = models.ForeignKey('CartPosition', null=True, blank=True)
|
||||||
|
question = models.ForeignKey(Question)
|
||||||
|
answer = models.TextField()
|
||||||
|
|
||||||
|
|
||||||
|
class OrderPosition(models.Model):
|
||||||
|
"""
|
||||||
|
An OrderPosition is one line of an order, representing one ordered items
|
||||||
|
of a specified type (or variation).
|
||||||
|
|
||||||
|
Important: An OrderPosition holds its total monetary value, as an order is a
|
||||||
|
piece of 'history' and must not change due to a change in item prices.
|
||||||
|
"""
|
||||||
|
order = models.ForeignKey(
|
||||||
|
Order,
|
||||||
|
verbose_name=_("Order")
|
||||||
|
)
|
||||||
|
item = models.ForeignKey(
|
||||||
|
Item,
|
||||||
|
verbose_name=_("Item")
|
||||||
|
)
|
||||||
|
variation = models.ForeignKey(
|
||||||
|
ItemVariation,
|
||||||
|
null=True, blank=True,
|
||||||
|
verbose_name=_("Variation")
|
||||||
|
)
|
||||||
|
price = models.DecimalField(
|
||||||
|
decimal_places=2, max_digits=10,
|
||||||
|
verbose_name=_("Price")
|
||||||
|
)
|
||||||
|
answers = models.ManyToManyField(
|
||||||
|
Question,
|
||||||
|
through=QuestionAnswer,
|
||||||
|
verbose_name=_("Answers")
|
||||||
|
)
|
||||||
|
|
||||||
|
class Meta:
|
||||||
|
verbose_name = _("Order position")
|
||||||
|
verbose_name_plural = _("Order positions")
|
||||||
|
|
||||||
|
|
||||||
|
class CartPosition(models.Model):
|
||||||
|
"""
|
||||||
|
A cart position is similar to a order line, except that it is not
|
||||||
|
yet part of a binding order but just placed by some user in his or
|
||||||
|
her cart. It therefore normally has a much shorter expiration time
|
||||||
|
than an ordered position, but still blocks an item in the quota pool
|
||||||
|
as we do not want to throw out users while they're clicking through
|
||||||
|
the checkout process.
|
||||||
|
"""
|
||||||
|
event = models.ForeignKey(
|
||||||
|
Event,
|
||||||
|
verbose_name=_("Event")
|
||||||
|
)
|
||||||
|
user = models.ForeignKey(
|
||||||
|
User, null=True, blank=True,
|
||||||
|
verbose_name=_("User")
|
||||||
|
)
|
||||||
|
session = models.CharField(
|
||||||
|
max_length=255, null=True, blank=True,
|
||||||
|
verbose_name=_("Session key")
|
||||||
|
)
|
||||||
|
item = models.ForeignKey(
|
||||||
|
Item,
|
||||||
|
verbose_name=_("Item")
|
||||||
|
)
|
||||||
|
variation = models.ForeignKey(
|
||||||
|
ItemVariation,
|
||||||
|
null=True, blank=True,
|
||||||
|
verbose_name=_("Variation")
|
||||||
|
)
|
||||||
|
total = models.DecimalField(
|
||||||
|
decimal_places=2, max_digits=10,
|
||||||
|
verbose_name=_("Price")
|
||||||
|
)
|
||||||
|
datetime = models.DateTimeField(
|
||||||
|
verbose_name=_("Datetime")
|
||||||
|
)
|
||||||
|
expires = models.DateTimeField(
|
||||||
|
verbose_name=_("Expiration date")
|
||||||
|
)
|
||||||
|
|
||||||
|
class Meta:
|
||||||
|
verbose_name = _("Cart position")
|
||||||
|
verbose_name_plural = _("Cart positions")
|
||||||
|
|||||||
@@ -0,0 +1,25 @@
|
|||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
from __future__ import unicode_literals
|
||||||
|
|
||||||
|
from django.db import models, migrations
|
||||||
|
import tixlbase.models
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('timerestriction', '0003_auto_20141013_1811'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name='timerestriction',
|
||||||
|
name='item',
|
||||||
|
field=models.ForeignKey(null=True, blank=True, related_name='restrictions_timerestriction_timerestriction', to='tixlbase.Item', verbose_name='Item'),
|
||||||
|
),
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name='timerestriction',
|
||||||
|
name='variations',
|
||||||
|
field=tixlbase.models.VariationsField(related_name='restrictions_timerestriction_timerestriction', to='tixlbase.ItemVariation', blank=True, verbose_name='Variations'),
|
||||||
|
),
|
||||||
|
]
|
||||||
Reference in New Issue
Block a user