Submitting orders

This commit is contained in:
Raphael Michel
2015-03-08 11:20:17 +01:00
parent 62b82bc852
commit a08b43ad45
8 changed files with 237 additions and 15 deletions

View File

@@ -0,0 +1,24 @@
# -*- coding: utf-8 -*-
from __future__ import unicode_literals
from django.db import models, migrations
class Migration(migrations.Migration):
dependencies = [
('pretixbase', '0014_auto_20150305_2310'),
]
operations = [
migrations.AddField(
model_name='order',
name='payment_provider',
field=models.CharField(blank=True, max_length=255, null=True, verbose_name='Payment provider'),
),
migrations.AlterField(
model_name='order',
name='datetime',
field=models.DateTimeField(verbose_name='Date'),
),
]

View File

@@ -0,0 +1,26 @@
# -*- coding: utf-8 -*-
from __future__ import unicode_literals
from django.db import models, migrations
class Migration(migrations.Migration):
dependencies = [
('pretixbase', '0015_auto_20150308_0953'),
]
operations = [
migrations.AddField(
model_name='order',
name='code',
field=models.CharField(max_length=16, verbose_name='Order code', default=''),
preserve_default=False,
),
migrations.AddField(
model_name='order',
name='payment_fee',
field=models.DecimalField(max_digits=10, verbose_name='Payment method fee', decimal_places=2, default=0),
preserve_default=False,
),
]

View File

@@ -1,6 +1,7 @@
from itertools import product
import copy
import uuid
import random
import time
from django.db import models
@@ -1219,8 +1220,9 @@ class Order(Versionable):
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.
An order -- like all objects -- has an ID, which is globally unique,
but also a code, which is shorter and easier to memorize, but only
unique among a single conference.
"""
STATUS_PENDING = "n"
@@ -1234,6 +1236,10 @@ class Order(Versionable):
(STATUS_CANCELLED, _("cancelled")),
)
code = models.CharField(
max_length=16,
verbose_name=_("Order code")
)
status = models.CharField(
max_length=3,
choices=STATUS_CHOICE,
@@ -1248,7 +1254,6 @@ class Order(Versionable):
verbose_name=_("User")
)
datetime = models.DateTimeField(
auto_now_add=True,
verbose_name=_("Date")
)
expires = models.DateTimeField(
@@ -1258,6 +1263,15 @@ class Order(Versionable):
verbose_name=_("Payment date"),
null=True, blank=True
)
payment_provider = models.CharField(
null=True, blank=True,
max_length=255,
verbose_name=_("Payment provider")
)
payment_fee = models.DecimalField(
decimal_places=2, max_digits=10,
verbose_name=_("Payment method fee")
)
payment_info = models.TextField(
verbose_name=_("Payment information"),
null=True, blank=True
@@ -1271,6 +1285,30 @@ class Order(Versionable):
verbose_name = _("Order")
verbose_name_plural = _("Orders")
def str(self):
return self.full_code
@property
def full_code(self):
"""
A order code which is unique among all events of a single organizer,
built by contatenating the event slug and the order code.
"""
return self.event.slug.upper() + self.code
def save(self, *args, **kwargs):
if not self.code:
self.assign_code()
super().save(*args, **kwargs)
def assign_code(self):
charset = list('ABCDEFGHKLMNPQRSTUVWXYZ23456789')
while True:
code = "".join([random.choice(charset) for i in range(5)])
if not Order.objects.filter(event=self.event, code=code).exists():
self.code = code
return
class QuestionAnswer(Versionable):
"""

View File

@@ -98,15 +98,15 @@ class BasePaymentProvider:
ctx = Context({'request': request, 'form': form})
return template.render(ctx)
def checkout_prepare(self, request, total):
def checkout_prepare(self, request, total) -> "bool|HttpResponse":
"""
Will be called if the user selects this provider as his payment method.
If the payment provider provides a form to the user to enter payment data,
this method should at least store the user's input into his session.
It should return True or False, depending of the validity of the user's input,
if the frontend should continue with default behaviour, or a custom HTTP response
(for example, a redirect), if you need special behaviour.
if the frontend should continue with default behaviour, or a redirect URL,
if you need special behaviour.
On errors, it should use Django's message framework to display an error message
to the user (or the normal form validation error messages).
@@ -121,10 +121,25 @@ class BasePaymentProvider:
else:
return False
def checkout_is_valid_session(self, request):
def checkout_is_valid_session(self, request) -> bool:
"""
This is called at the time the user tries to place the order. It should return
True, if the user's session is valid and all data your payment provider requires
in future steps is present.
"""
raise NotImplementedError()
def checkout_perform(self, request, order) -> str:
"""
Will be called if the user submitted his order successfully to initiate the
payment process.
It should return a custom redirct URL, if you need special behaviour, or None to
continue with default behaviour.
On errors, it should use Django's message framework to display an error message
to the user (or the normal form validation error messages).
:param order: The order object
"""
return None

View File

@@ -10,6 +10,7 @@ DEFAULTS = {
'max_items_per_order': '10',
'attendee_names_asked': 'True',
'attendee_names_required': 'False',
'reservation_time': '30',
}