Add quota and order models

This commit is contained in:
Raphael Michel
2014-10-17 23:55:54 +02:00
parent 29b1352377
commit ed4789dc4f
3 changed files with 354 additions and 3 deletions

View 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.'),
),
]

View File

@@ -266,7 +266,7 @@ class Event(models.Model):
verbose_name=_("Start of presale"),
help_text=_("No items will be sold before this date."),
)
payment_term_days = models.IntegerField(
payment_term_days = models.PositiveIntegerField(
default=14,
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."),
@@ -709,13 +709,14 @@ class BaseRestriction(models.Model):
)
item = models.ForeignKey(
Item,
blank=True,
null=True,
blank=True, null=True,
verbose_name=_("Item"),
related_name="restrictions_%(app_label)s_%(class)s",
)
variations = VariationsField(
ItemVariation,
blank=True,
verbose_name=_("Variations"),
related_name="restrictions_%(app_label)s_%(class)s",
)
@@ -728,3 +729,203 @@ class BaseRestriction(models.Model):
if self.event:
self.event.get_cache().clear()
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")