Refactor mark_paid out of models

This commit is contained in:
Raphael Michel
2015-06-03 13:58:03 +02:00
parent 49ea85caee
commit fc907a2ec7
9 changed files with 79 additions and 203 deletions

View File

@@ -1,134 +0,0 @@
from django.contrib import admin
from django.contrib.auth.admin import UserAdmin
from django.utils.translation import ugettext as _
from django import forms
from pretix.base.models import (
User, Organizer, OrganizerPermission, Event, EventPermission,
Property, PropertyValue, Item, ItemVariation, ItemCategory
)
class PretixUserCreationForm(forms.ModelForm):
"""
A form that creates a user, with no privileges, from the given username and
password.
"""
error_messages = {
'password_mismatch': _("The two password fields didn't match."),
}
password1 = forms.CharField(label=_("Password"),
widget=forms.PasswordInput)
password2 = forms.CharField(label=_("Password confirmation"),
widget=forms.PasswordInput,
help_text=_("Enter the same password as above, for verification."))
class Meta:
model = User
fields = ("email", "username", "event")
def clean_password2(self):
password1 = self.cleaned_data.get("password1")
password2 = self.cleaned_data.get("password2")
if password1 and password2 and password1 != password2:
raise forms.ValidationError(
self.error_messages['password_mismatch'],
code='password_mismatch',
)
return password2
def save(self, commit=True):
user = super(PretixUserCreationForm, self).save(commit=False)
user.set_password(self.cleaned_data["password1"])
if commit:
user.save()
return user
class PretixUserAdmin(UserAdmin):
fieldsets = (
(None, {'fields': ('identifier', 'event', 'username', 'password')}),
(_('Personal info'), {'fields': ('familyname', 'givenname', 'email')}),
(_('Locale'), {'fields': ('locale', 'timezone')}),
(_('Permissions'), {'fields': ('is_active', 'is_staff',
'groups', 'user_permissions')}),
)
list_display = ('identifier', 'event', 'username', 'email', 'givenname', 'familyname', 'is_staff')
search_fields = ('identifier', 'username', 'givenname', 'familyname', 'email')
ordering = ('identifier',)
list_filter = ('is_staff', 'is_active', 'groups')
add_form = PretixUserCreationForm
class OrganizerPermissionInline(admin.TabularInline):
model = OrganizerPermission
extra = 2
class OrganizerAdmin(admin.ModelAdmin):
model = Organizer
inlines = [OrganizerPermissionInline]
list_display = ('name', 'slug')
search_fields = ('name', 'slug')
class EventPermissionInline(admin.TabularInline):
model = EventPermission
extra = 2
class EventAdmin(admin.ModelAdmin):
model = Event
inlines = [EventPermissionInline]
list_display = ('name', 'slug', 'organizer', 'date_from')
search_fields = ('name', 'slug')
list_filter = ('date_from', 'currency')
class PropertyValueInline(admin.StackedInline):
model = PropertyValue
extra = 4
class PropertyAdmin(admin.ModelAdmin):
model = Property
inlines = [PropertyValueInline]
list_display = ('name', 'event')
search_fields = ('name', 'event')
class ItemCategoryAdmin(admin.ModelAdmin):
model = ItemCategory
list_display = ('name', 'event')
search_fields = ('name', 'event')
class ItemVariationInline(admin.TabularInline):
model = ItemVariation
extra = 4
class ItemAdmin(admin.ModelAdmin):
model = Item
inlines = [ItemVariationInline]
list_display = ('name', 'event', 'category')
search_fields = ('name', 'event', 'category', 'short_description')
admin.site.register(User, PretixUserAdmin)
admin.site.register(Organizer, OrganizerAdmin)
admin.site.register(Event, EventAdmin)
admin.site.register(Property, PropertyAdmin)
admin.site.register(Item, ItemAdmin)
admin.site.register(ItemCategory, ItemCategoryAdmin)

View File

@@ -5,7 +5,6 @@ import uuid
import random
import time
from django.core.urlresolvers import reverse
from django.db import models
from django.conf import settings
from django.contrib.auth.models import AbstractBaseUser, BaseUserManager, PermissionsMixin
@@ -1660,58 +1659,6 @@ class Order(Versionable):
quota.release()
return True, quotas_locked
def mark_paid(self, provider=None, info=None, date=None, manual=None, force=False):
"""
Mark this order as paid. This clones the order object, sets the payment provider,
info and date and returns the cloned order object.
:param provider: The payment provider that marked this as paid
:type provider: str
:param info: The information to store in order.payment_info
:type info: str
:param date: The date the payment was received (if you pass ``None``, the current
time will be used).
:type date: datetime
:param force: Whether this payment should be marked as paid even if no remaining
quota is available (default: ``False``).
:type force: boolean
:raises Quota.QuotaExceededException: if the quota is exceeded and ``force`` is ``False``
"""
can_be_paid, quotas_locked = self._can_be_paid(keep_locked=True)
if not force and can_be_paid is not True:
raise Quota.QuotaExceededException(can_be_paid)
order = self.clone()
order.payment_provider = provider or order.payment_provider
order.payment_info = info or order.payment_info
order.payment_date = date or now()
if manual is not None:
order.payment_manual = manual
order.status = Order.STATUS_PAID
order.save()
if quotas_locked:
for quota in quotas_locked:
quota.release()
from pretix.base.mail import mail
mail(
order.user, _('Payment received for your order: %(code)s') % {'code': order.code},
'pretixpresale/email/order_paid.txt',
{
'user': order.user,
'order': order,
'event': order.event,
'url': settings.SITE_URL + reverse('presale:event.order', kwargs={
'event': order.event.slug,
'organizer': order.event.organizer.slug,
'order': order.code
}),
'downloads': order.event.settings.get('ticket_download', as_type=bool)
},
order.event
)
return order
class QuestionAnswer(Versionable):
"""

View File

@@ -244,11 +244,11 @@ class BasePaymentProvider:
containing an URL the user will be redirected to. If you are done with your process
you should return the user to the order's detail page.
If the payment is completed, you should call ``order.mark_paid(provider, info)``
If the payment is completed, you should call ``pretix.bsae.services.orders.mark_order_paid(order, provider, info)``
with ``provider`` being your :py:attr:`identifier` and ``info`` being any string
you might want to store for later usage. Please note, that if you want to store
something inside ``order.payment_info``, please do it after the ``mark_paid`` call,
as this call does a object clone for you. Please also note that ``mark_paid`` might
something inside ``order.payment_info``, please do it after the ``mark_order_paid`` call,
as this call does a object clone for you. Please also note that ``mark_order_paid`` might
raise a ``Quota.QuotaExceededException`` if (and only if) the payment term of this
order is over and some of the items are sold out. You should use the exception message
to display a meaningful error to the user.

View File

@@ -0,0 +1,58 @@
from django.conf import settings
from django.core.urlresolvers import reverse
from django.utils.timezone import now
from pretix.base.models import Order, Quota
from django.utils.translation import ugettext_lazy as _
def mark_order_paid(order, provider=None, info=None, date=None, manual=None, force=False):
"""
Marks an order as paid. This clones the order object, sets the payment provider,
info and date and returns the cloned order object.
:param provider: The payment provider that marked this as paid
:type provider: str
:param info: The information to store in order.payment_info
:type info: str
:param date: The date the payment was received (if you pass ``None``, the current
time will be used).
:type date: datetime
:param force: Whether this payment should be marked as paid even if no remaining
quota is available (default: ``False``).
:type force: boolean
:raises Quota.QuotaExceededException: if the quota is exceeded and ``force`` is ``False``
"""
can_be_paid, quotas_locked = order._can_be_paid(keep_locked=True)
if not force and can_be_paid is not True:
raise Quota.QuotaExceededException(can_be_paid)
order = order.clone()
order.payment_provider = provider or order.payment_provider
order.payment_info = info or order.payment_info
order.payment_date = date or now()
if manual is not None:
order.payment_manual = manual
order.status = Order.STATUS_PAID
order.save()
if quotas_locked:
for quota in quotas_locked:
quota.release()
from pretix.base.mail import mail
mail(
order.user, _('Payment received for your order: %(code)s') % {'code': order.code},
'pretixpresale/email/order_paid.txt',
{
'user': order.user,
'order': order,
'event': order.event,
'url': settings.SITE_URL + reverse('presale:event.order', kwargs={
'event': order.event.slug,
'organizer': order.event.organizer.slug,
'order': order.code
}),
'downloads': order.event.settings.get('ticket_download', as_type=bool)
},
order.event
)
return order

View File

@@ -9,6 +9,7 @@ from django.shortcuts import redirect, render
from django.utils.functional import cached_property
from django.views.generic import ListView, DetailView, TemplateView
from pretix.base.models import Order, Quota, OrderPosition
from pretix.base.services.orders import mark_order_paid
from pretix.base.signals import register_payment_providers
from pretix.control.forms.orders import ExtendForm
from pretix.control.permissions import EventPermissionRequiredMixin
@@ -107,7 +108,7 @@ class OrderTransition(OrderView):
to = self.request.POST.get('status', '')
if self.order.status == 'n' and to == 'p':
try:
self.order.mark_paid(manual=True)
mark_order_paid(self.order, manual=True)
except Quota.QuotaExceededException as e:
messages.error(self.request, str(e))
else:

View File

@@ -9,6 +9,7 @@ from django.shortcuts import redirect, render
from django.utils.timezone import now
from django.views.generic import TemplateView
from pretix.base.models import Order, Quota
from pretix.base.services.orders import mark_order_paid
from pretix.control.permissions import EventPermissionRequiredMixin
from pretix.plugins.banktransfer import csvimport, mt940import
from django.utils.translation import ugettext_lazy as _
@@ -36,7 +37,7 @@ class ImportView(EventPermissionRequiredMixin, TemplateView):
some_failed = False
for order in orders:
try:
order.mark_paid(provider='banktransfer', info=json.dumps({
mark_order_paid(order, provider='banktransfer', info=json.dumps({
'reference': self.request.POST.get('reference_%s' % order.code),
'date': self.request.POST.get('date_%s' % order.code),
'payer': self.request.POST.get('payer_%s' % order.code),

View File

@@ -1,16 +1,16 @@
from collections import OrderedDict
import json
import logging
from django.contrib import messages
from django.core.urlresolvers import reverse
from django.template.loader import get_template
from django.utils.translation import ugettext_lazy as _
from django.utils.translation import ugettext as __
from django import forms
import paypalrestsdk
from pretix.base.models import Quota
from pretix.base.services.orders import mark_order_paid
from pretix.base.payment import BasePaymentProvider
@@ -177,7 +177,7 @@ class Paypal(BasePaymentProvider):
return
try:
order.mark_paid('paypal', json.dumps(payment.to_dict()))
mark_order_paid(order, 'paypal', json.dumps(payment.to_dict()))
messages.success(request, _('We successfully received your payment. Thank you!'))
except Quota.QuotaExceededException as e:
messages.error(request, str(e))

View File

@@ -1,16 +1,18 @@
from collections import OrderedDict
import json
import logging
from django.contrib import messages
from django.core.urlresolvers import reverse
from django.template.loader import get_template
from django.utils.translation import ugettext_lazy as _
from django import forms
from pretix.base.models import Quota
from pretix.base.services.orders import mark_order_paid
import stripe
from pretix.base.payment import BasePaymentProvider
logger = logging.getLogger('pretix.plugins.stripe')
@@ -99,7 +101,7 @@ class Stripe(BasePaymentProvider):
else:
if charge.status == 'succeeded' and charge.paid:
try:
order.mark_paid('paypal', str(charge))
mark_order_paid(order, 'paypal', str(charge))
messages.success(request, _('We successfully received your payment. Thank you!'))
except Quota.QuotaExceededException as e:
messages.error(request, str(e))

View File

@@ -1,11 +1,12 @@
from datetime import timedelta
from django.test import TestCase
from django.utils.timezone import now
from pretix.base.models import (
Event, Organizer, Item, ItemVariation,
Property, PropertyValue, User, Quota,
Order, OrderPosition, CartPosition)
from pretix.base.services.orders import mark_order_paid
from pretix.base.types import VariationDict
@@ -314,14 +315,14 @@ class OrderTestCase(BaseQuotaTestCase):
def test_paid_in_time(self):
self.quota.size = 0
self.quota.save()
self.order.mark_paid()
mark_order_paid(self.order)
self.order = Order.objects.current.get(identity=self.order.identity)
self.assertEqual(self.order.status, Order.STATUS_PAID)
def test_paid_expired_available(self):
self.order.expires = now() - timedelta(days=2)
self.order.save()
self.order.mark_paid()
mark_order_paid(self.order)
self.order = Order.objects.current.get(identity=self.order.identity)
self.assertEqual(self.order.status, Order.STATUS_PAID)
@@ -331,7 +332,7 @@ class OrderTestCase(BaseQuotaTestCase):
self.quota.size = 1
self.quota.save()
try:
self.order.mark_paid()
mark_order_paid(self.order)
self.assertFalse(True, 'This should have raised an exception.')
except Quota.QuotaExceededException:
pass
@@ -344,7 +345,7 @@ class OrderTestCase(BaseQuotaTestCase):
self.quota.size = 0
self.quota.save()
try:
self.order.mark_paid()
mark_order_paid(self.order)
self.assertFalse(True, 'This should have raised an exception.')
except Quota.QuotaExceededException:
pass
@@ -356,6 +357,6 @@ class OrderTestCase(BaseQuotaTestCase):
self.order.save()
self.quota.size = 0
self.quota.save()
self.order.mark_paid(force=True)
mark_order_paid(self.order, force=True)
self.order = Order.objects.current.get(identity=self.order.identity)
self.assertEqual(self.order.status, Order.STATUS_PAID)