forked from CGM_Public/pretix_original
Updated models and signals documentation
This commit is contained in:
@@ -31,3 +31,36 @@ will have an attribute ``event``.
|
|||||||
|
|
||||||
``pretix.control.signals.nav_event``:
|
``pretix.control.signals.nav_event``:
|
||||||
The sidebar navigation when the admin has selected an event.
|
The sidebar navigation when the admin has selected an event.
|
||||||
|
|
||||||
|
Order events
|
||||||
|
------------
|
||||||
|
|
||||||
|
There are multiple signals that will be sent out in the ordering cycle:
|
||||||
|
|
||||||
|
``pretix.base.signals.order_placed``:
|
||||||
|
Sent out every time an order has been created. Provides the ``order`` as the only
|
||||||
|
keyword argument.
|
||||||
|
|
||||||
|
``pretix.base.signals.order_paid``:
|
||||||
|
Sent out every time an order has been paid. Provides the ``order`` as the only
|
||||||
|
keyword argument.
|
||||||
|
|
||||||
|
|
||||||
|
Displaying of log entries
|
||||||
|
-------------------------
|
||||||
|
|
||||||
|
To display an instance of the ``LogEntry`` model to a human user,
|
||||||
|
``pretix.base.signals.logentry_display`` will be sent out with a ``logentry`` argument.
|
||||||
|
|
||||||
|
The first received response that is not ``None`` will be used to display the log entry
|
||||||
|
to the user.
|
||||||
|
|
||||||
|
|
||||||
|
Periodic tasks
|
||||||
|
--------------
|
||||||
|
|
||||||
|
The ``pretix.base.signals.periodic_task`` is a regular django signal (no pretix event
|
||||||
|
signal) that we send out every time the periodic task cronjob runs. This interval
|
||||||
|
is not sharply defined, it can be everything between a minute and a day. The actions
|
||||||
|
you perform should be idempotent, i.e. it should not make a difference if this is send
|
||||||
|
out more often than expected.
|
||||||
|
|||||||
@@ -38,13 +38,8 @@ Items and variations
|
|||||||
|
|
||||||
The purpose of pretix is to sell **items** (which belong to **events**) to **users**.
|
The purpose of pretix is to sell **items** (which belong to **events**) to **users**.
|
||||||
An **item** is a abstract thing, popular examples being event tickets or a piece of
|
An **item** is a abstract thing, popular examples being event tickets or a piece of
|
||||||
merchandise, like 'T-shirt'. An **item** can have multiple **properties** with multiple
|
merchandise, like 'T-shirt'. An **item** can have multiple **variations**. For example,
|
||||||
**values** each. For example, the **item** 'T-Shirt' could have the **property** 'Size'
|
the **item** 'T-Shirt' could have the **variations** S', 'M' and 'L'.
|
||||||
with **values** 'S', 'M' and 'L' and the **property** 'Color' with **values** 'black'
|
|
||||||
and 'blue'.
|
|
||||||
|
|
||||||
Any combination of those **values** is called a **variation**. Using the examples from
|
|
||||||
above, a possible **variation** would be 'T-Shirt, S, blue'.
|
|
||||||
|
|
||||||
Questions
|
Questions
|
||||||
^^^^^^^^^
|
^^^^^^^^^
|
||||||
@@ -61,22 +56,22 @@ special care in the implementation to never sell more tickets than allowed, even
|
|||||||
|
|
||||||
* There is a concept of **quotas**. A quota is basically a number of items combined with information
|
* There is a concept of **quotas**. A quota is basically a number of items combined with information
|
||||||
about how many of them are still available.
|
about how many of them are still available.
|
||||||
* Every time a user places a item in the cart, a **cart lock** is created, reducing the number of
|
* Every time a user places a item in the cart, a **cart position** is created, reducing the number of
|
||||||
available items in the pool by one. The lock is valid for a fixed time (e.g. 30 minutes), but not
|
available items in the pool by one. The position is valid for a fixed time (e.g. 30 minutes), but not
|
||||||
instantly deleted after those 30 minutes (we'll get to that).
|
instantly deleted after those 30 minutes (we'll get to that).
|
||||||
* Every time a user places a binding order, the lock object is replaced by an **order** which behaves
|
* Every time a user places a binding order, the position object is replaced by an **order position** which behaves
|
||||||
much the same as the lock. It reduces the number of available item and is valid for a fixed time, this
|
much the same as the cart position. It reduces the number of available item and is valid for a fixed time, this
|
||||||
time for the configured payment term (e.g. 14 days).
|
time for the configured payment term (e.g. 14 days).
|
||||||
* If the order is being paid, the **order** becomes permanent.
|
* If the order is being paid, the **order** becomes permanent.
|
||||||
* Once there are no available tickets left and user A wants to buy a ticket, he can do so, as long as
|
* Once there are no available tickets left and user A wants to buy a ticket, he can do so, as long as
|
||||||
there are *expired* cart locks in the system. In this case, user A gets a new cart lock, so that there
|
there are *expired* cart position in the system. In this case, user A gets a new cart position, so that there
|
||||||
are more cart locks than available tickets and therefore have to remove one of the expired cart locks.
|
are more cart position than available tickets and therefore have to remove one of the expired cart positions.
|
||||||
However, we do not choose one by random, but keep the surplus in a way that leads to the deletion
|
However, we do not choose one by random, but keep the surplus in a way that leads to the deletion
|
||||||
of the cart lock of the user who tries *last* to use his lock.
|
of the cart position f the user who tries *last* to use his cart position.
|
||||||
* The same goes for orders which are not paid within the specified timeframe. This policy allows the organizer to
|
* The same goes for orders which are not paid within the specified timeframe. This policy allows the organizer to
|
||||||
sell as much items as possible. Moreover, it guarantees the users to get their items if they check out within the validity
|
sell as much items as possible. Moreover, it guarantees the users to get their items if they check out within the validity
|
||||||
period of their locks and pay within the validity period of their orders. It does not guarantee them anything
|
period of their positions and pay within the validity period of their orders. It does not guarantee them anything
|
||||||
any longer, but it tries to be *as tolerant as possible* to users who are paying after their payment
|
any longer, but it tries to be *as tolerant as possible* to users who are paying after their payment
|
||||||
period or click checkout after the expiry of their lock.
|
period or click checkout after the expiry of their position.
|
||||||
* The same quota can apply to multiple items and one item can be affected by multiple quotas.
|
* The same quota can apply to multiple items and one item can be affected by multiple quotas.
|
||||||
|
|
||||||
|
|||||||
@@ -6,7 +6,6 @@ Contents:
|
|||||||
.. toctree::
|
.. toctree::
|
||||||
:maxdepth: 2
|
:maxdepth: 2
|
||||||
|
|
||||||
goals
|
|
||||||
concepts
|
concepts
|
||||||
setup
|
setup
|
||||||
style
|
style
|
||||||
|
|||||||
@@ -55,7 +55,7 @@ Carts and Orders
|
|||||||
:members:
|
:members:
|
||||||
|
|
||||||
.. autoclass:: pretix.base.models.AbstractPosition
|
.. autoclass:: pretix.base.models.AbstractPosition
|
||||||
:members:
|
:members:
|
||||||
|
|
||||||
.. autoclass:: pretix.base.models.OrderPosition
|
.. autoclass:: pretix.base.models.OrderPosition
|
||||||
:members:
|
:members:
|
||||||
@@ -72,6 +72,15 @@ Logging
|
|||||||
.. autoclass:: pretix.base.models.LogEntry
|
.. autoclass:: pretix.base.models.LogEntry
|
||||||
:members:
|
:members:
|
||||||
|
|
||||||
|
Invoicing
|
||||||
|
---------
|
||||||
|
|
||||||
|
.. autoclass:: pretix.base.models.Invoice
|
||||||
|
:members:
|
||||||
|
|
||||||
|
.. autoclass:: pretix.base.models.InvoiceLine
|
||||||
|
:members:
|
||||||
|
|
||||||
Vouchers
|
Vouchers
|
||||||
--------
|
--------
|
||||||
|
|
||||||
|
|||||||
@@ -17,6 +17,22 @@ def invoice_filename(instance, filename: str) -> str:
|
|||||||
|
|
||||||
|
|
||||||
class Invoice(models.Model):
|
class Invoice(models.Model):
|
||||||
|
"""
|
||||||
|
Represents an invoice that is issued because of an order. Because invoices are legally required
|
||||||
|
not to change, this object duplicates a log of data (e.g. the invoice address).
|
||||||
|
|
||||||
|
:param order: The associated order
|
||||||
|
:param event: The event this belongs to (for convenience)
|
||||||
|
:param invoice_no: The human-readable, event-unique invoice number
|
||||||
|
:param is_cancellation: Whether or not this is a cancellation instead of an invoice
|
||||||
|
:param refers: A link to another invoice this invoice referse to, e.g. the cancelled invoice in an cancellation
|
||||||
|
:param invoice_from: The sender address
|
||||||
|
:param invoice_to: The receiver address
|
||||||
|
:param date: The invoice date
|
||||||
|
:param locale: The locale in which the invoice should be printed
|
||||||
|
:param additional_text: Additional text for the invoice
|
||||||
|
:param file: The filename of the rendered invoice
|
||||||
|
"""
|
||||||
order = models.ForeignKey('Order', related_name='invoices', db_index=True)
|
order = models.ForeignKey('Order', related_name='invoices', db_index=True)
|
||||||
event = models.ForeignKey('Event', related_name='invoices', db_index=True)
|
event = models.ForeignKey('Event', related_name='invoices', db_index=True)
|
||||||
invoice_no = models.PositiveIntegerField(db_index=True)
|
invoice_no = models.PositiveIntegerField(db_index=True)
|
||||||
@@ -48,6 +64,9 @@ class Invoice(models.Model):
|
|||||||
|
|
||||||
@property
|
@property
|
||||||
def number(self):
|
def number(self):
|
||||||
|
"""
|
||||||
|
Returns the invoice number in a human-readable way with the event slug prepended.
|
||||||
|
"""
|
||||||
return '%s-%05d' % (self.event.slug.upper(), self.invoice_no)
|
return '%s-%05d' % (self.event.slug.upper(), self.invoice_no)
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
@@ -55,6 +74,15 @@ class Invoice(models.Model):
|
|||||||
|
|
||||||
|
|
||||||
class InvoiceLine(models.Model):
|
class InvoiceLine(models.Model):
|
||||||
|
"""
|
||||||
|
One position listed on an invoice.
|
||||||
|
|
||||||
|
:param invoice: The invoice this belongs to
|
||||||
|
:param description: The item description
|
||||||
|
:param gross_value: The gross value
|
||||||
|
:param tax_value: The included tax (as an absolute value)
|
||||||
|
:param tax_rate: The applied tax rate in percent
|
||||||
|
"""
|
||||||
invoice = models.ForeignKey('Invoice', related_name='lines')
|
invoice = models.ForeignKey('Invoice', related_name='lines')
|
||||||
description = models.TextField()
|
description = models.TextField()
|
||||||
gross_value = models.DecimalField(max_digits=10, decimal_places=2)
|
gross_value = models.DecimalField(max_digits=10, decimal_places=2)
|
||||||
|
|||||||
@@ -9,6 +9,7 @@ class LogEntry(models.Model):
|
|||||||
in the database. This uses django.contrib.contenttypes to allow a
|
in the database. This uses django.contrib.contenttypes to allow a
|
||||||
relation to an arbitrary database object.
|
relation to an arbitrary database object.
|
||||||
|
|
||||||
|
:param datatime: The timestamp of the logged action
|
||||||
:param user: The user that performed the action
|
:param user: The user that performed the action
|
||||||
:type user: User
|
:type user: User
|
||||||
:param action_type: The type of action that has been performed. This is
|
:param action_type: The type of action that has been performed. This is
|
||||||
|
|||||||
@@ -52,6 +52,8 @@ class Order(LoggedModel):
|
|||||||
:type email: str
|
:type email: str
|
||||||
:param locale: The locale of this order
|
:param locale: The locale of this order
|
||||||
:type locale: str
|
:type locale: str
|
||||||
|
:param secret: A secret string that is required to modify the order
|
||||||
|
:type secret: str
|
||||||
:param datetime: The datetime of the order placement
|
:param datetime: The datetime of the order placement
|
||||||
:type datetime: datetime
|
:type datetime: datetime
|
||||||
:param expires: The date until this order has to be paid to guarantee the
|
:param expires: The date until this order has to be paid to guarantee the
|
||||||
@@ -62,6 +64,10 @@ class Order(LoggedModel):
|
|||||||
:type payment_provider: str
|
:type payment_provider: str
|
||||||
:param payment_fee: The payment fee calculated at checkout time
|
:param payment_fee: The payment fee calculated at checkout time
|
||||||
:type payment_fee: decimal.Decimal
|
:type payment_fee: decimal.Decimal
|
||||||
|
:param payment_fee_tax_value: The absolute amound of tax included in the payment fee
|
||||||
|
:type payment_fee_tax_value: decimal.Decimal
|
||||||
|
:param payment_fee_tax_rate: The tax rate applied to the payment fee (in percent)
|
||||||
|
:type payment_fee_tax_rate: decimal.Decimal
|
||||||
:param payment_info: Arbitrary information stored by the payment provider
|
:param payment_info: Arbitrary information stored by the payment provider
|
||||||
:type payment_info: str
|
:type payment_info: str
|
||||||
:param total: The total amount of the order, including the payment fee
|
:param total: The total amount of the order, including the payment fee
|
||||||
@@ -170,6 +176,10 @@ class Order(LoggedModel):
|
|||||||
super().save(*args, **kwargs)
|
super().save(*args, **kwargs)
|
||||||
|
|
||||||
def _calculate_tax(self):
|
def _calculate_tax(self):
|
||||||
|
"""
|
||||||
|
Calculates the taxes on the payment fees and sets the parameters payment_fee_tax_rate
|
||||||
|
and payment_fee_tax_value accordingly.
|
||||||
|
"""
|
||||||
self.payment_fee_tax_rate = self.event.settings.get('tax_rate_default')
|
self.payment_fee_tax_rate = self.event.settings.get('tax_rate_default')
|
||||||
if self.payment_fee_tax_rate:
|
if self.payment_fee_tax_rate:
|
||||||
self.payment_fee_tax_value = round_decimal(
|
self.payment_fee_tax_value = round_decimal(
|
||||||
|
|||||||
@@ -20,6 +20,25 @@ def generate_code():
|
|||||||
|
|
||||||
|
|
||||||
class Voucher(LoggedModel):
|
class Voucher(LoggedModel):
|
||||||
|
"""
|
||||||
|
Represents a voucher. A voucher can reserve ticket quota or allow special prices.
|
||||||
|
|
||||||
|
:param event: The event this voucher is valid for
|
||||||
|
:param code: The secret voucher code
|
||||||
|
:param redeemed: Whether or not this voucher has already been redeemed
|
||||||
|
:param valid_until: The expiration date of this voucher (optional)
|
||||||
|
:param block_quota: If set to true, this voucher will reserve quota for its holder
|
||||||
|
:param allow_ignore_quota: If set to true, this voucher can be redeemed even if the event is sold out
|
||||||
|
:param price: If set, the voucher will allow the sale of associated items for this price
|
||||||
|
:param item: If set, the item to sell
|
||||||
|
:param variation: If set, the variation to sell
|
||||||
|
:param quota: If set, the quota to choose an item from
|
||||||
|
|
||||||
|
Various constraints apply:
|
||||||
|
|
||||||
|
* You can either select a quota or an item and you need to select one of those
|
||||||
|
* If you select an item that as variations but not select a variation, you cannot set block_quota
|
||||||
|
"""
|
||||||
event = models.ForeignKey(
|
event = models.ForeignKey(
|
||||||
Event,
|
Event,
|
||||||
on_delete=models.CASCADE,
|
on_delete=models.CASCADE,
|
||||||
@@ -116,11 +135,17 @@ class Voucher(LoggedModel):
|
|||||||
self.event.get_cache().delete('vouchers_exist')
|
self.event.get_cache().delete('vouchers_exist')
|
||||||
|
|
||||||
def is_ordered(self) -> int:
|
def is_ordered(self) -> int:
|
||||||
|
"""
|
||||||
|
Returns whether an order position exists that uses this voucher.
|
||||||
|
"""
|
||||||
return OrderPosition.objects.filter(
|
return OrderPosition.objects.filter(
|
||||||
voucher=self
|
voucher=self
|
||||||
).exists()
|
).exists()
|
||||||
|
|
||||||
def is_in_cart(self) -> int:
|
def is_in_cart(self) -> int:
|
||||||
|
"""
|
||||||
|
Returns whether a cart position exists that uses this voucher.
|
||||||
|
"""
|
||||||
return CartPosition.objects.filter(
|
return CartPosition.objects.filter(
|
||||||
voucher=self
|
voucher=self
|
||||||
).count()
|
).count()
|
||||||
|
|||||||
Reference in New Issue
Block a user