mirror of
https://github.com/pretix/pretix.git
synced 2026-08-29 13:44:40 +00:00
Added admin action to make an expired order pending again
This commit is contained in:
Binary file not shown.
|
Before Width: | Height: | Size: 32 KiB After Width: | Height: | Size: 42 KiB |
@@ -11,6 +11,7 @@ Pending --> Paid: successful payment
|
|||||||
Pending --> Expired: automatically\nor manually\non admin action
|
Pending --> Expired: automatically\nor manually\non admin action
|
||||||
Expired --> Paid: if payment is received\nonly if quota left
|
Expired --> Paid: if payment is received\nonly if quota left
|
||||||
Expired --> Canceled
|
Expired --> Canceled
|
||||||
|
Expired --> Pending: manually\non admin action
|
||||||
Paid --> Refunded: manually on\nadmin action\nor if an external\npayment provider\nnotifies about a\npayment refund
|
Paid --> Refunded: manually on\nadmin action\nor if an external\npayment provider\nnotifies about a\npayment refund
|
||||||
Pending --> Canceled: on admin or\ncustomer action
|
Pending --> Canceled: on admin or\ncustomer action
|
||||||
Paid -> Pending: manually on admin action
|
Paid -> Pending: manually on admin action
|
||||||
|
|||||||
@@ -286,8 +286,6 @@ class Order(LoggedModel):
|
|||||||
raise Quota.QuotaExceededException(error_messages['unavailable'])
|
raise Quota.QuotaExceededException(error_messages['unavailable'])
|
||||||
|
|
||||||
for quota in quotas:
|
for quota in quotas:
|
||||||
# Lock the quota, so no other thread is allowed to perform sales covered by this
|
|
||||||
# quota while we're doing so.
|
|
||||||
if quota.id not in quota_cache:
|
if quota.id not in quota_cache:
|
||||||
quota_cache[quota.id] = quota
|
quota_cache[quota.id] = quota
|
||||||
quota.cached_availability = quota.availability(now_dt)[1]
|
quota.cached_availability = quota.availability(now_dt)[1]
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
from django import forms
|
from django import forms
|
||||||
from django.core.exceptions import ValidationError
|
from django.core.exceptions import ValidationError
|
||||||
from django.db import models
|
from django.db import models
|
||||||
|
from django.utils.timezone import now
|
||||||
from django.utils.translation import ugettext_lazy as _
|
from django.utils.translation import ugettext_lazy as _
|
||||||
|
|
||||||
from pretix.base.forms import I18nModelForm
|
from pretix.base.forms import I18nModelForm
|
||||||
@@ -15,6 +16,12 @@ class ExtendForm(I18nModelForm):
|
|||||||
'expires': forms.DateTimeInput(attrs={'class': 'datetimepicker'}),
|
'expires': forms.DateTimeInput(attrs={'class': 'datetimepicker'}),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
def clean(self):
|
||||||
|
data = super().clean()
|
||||||
|
if data['expires'] < now():
|
||||||
|
raise ValidationError(_('The new expiry date needs to be in the future.'))
|
||||||
|
return data
|
||||||
|
|
||||||
|
|
||||||
class ExporterForm(forms.Form):
|
class ExporterForm(forms.Form):
|
||||||
|
|
||||||
|
|||||||
@@ -23,11 +23,11 @@
|
|||||||
<div class="btn-group" role="group">
|
<div class="btn-group" role="group">
|
||||||
{% if order.status == 'n' or order.status == 'e' %}
|
{% if order.status == 'n' or order.status == 'e' %}
|
||||||
<button name="status" value="p" class="btn btn-default">{% trans "Mark as paid" %}</button>
|
<button name="status" value="p" class="btn btn-default">{% trans "Mark as paid" %}</button>
|
||||||
{% endif %}
|
|
||||||
{% if order.status == 'n' %}
|
|
||||||
<a href="{% url "control:event.order.extend" event=request.event.slug organizer=request.event.organizer.slug code=order.code %}" class="btn btn-default">
|
<a href="{% url "control:event.order.extend" event=request.event.slug organizer=request.event.organizer.slug code=order.code %}" class="btn btn-default">
|
||||||
{% trans "Extend payment term" %}
|
{% trans "Extend payment term" %}
|
||||||
</a>
|
</a>
|
||||||
|
{% endif %}
|
||||||
|
{% if order.status == 'n' %}
|
||||||
<a href="{% url "control:event.order.transition" event=request.event.slug organizer=request.event.organizer.slug code=order.code %}?status=c" class="btn btn-default">
|
<a href="{% url "control:event.order.transition" event=request.event.slug organizer=request.event.organizer.slug code=order.code %}?status=c" class="btn btn-default">
|
||||||
{% trans "Cancel order" %}
|
{% trans "Cancel order" %}
|
||||||
</a>
|
</a>
|
||||||
|
|||||||
@@ -442,16 +442,12 @@ class OrderExtend(OrderView):
|
|||||||
permission = 'can_change_orders'
|
permission = 'can_change_orders'
|
||||||
|
|
||||||
def post(self, *args, **kwargs):
|
def post(self, *args, **kwargs):
|
||||||
if self.order.status != Order.STATUS_PENDING:
|
|
||||||
messages.error(self.request, _('This action is only allowed for pending orders.'))
|
|
||||||
return self._redirect_back()
|
|
||||||
oldvalue = self.order.expires
|
|
||||||
|
|
||||||
if self.form.is_valid():
|
if self.form.is_valid():
|
||||||
if oldvalue > now():
|
if self.order.status == Order.STATUS_PENDING:
|
||||||
messages.success(self.request, _('The payment term has been changed.'))
|
messages.success(self.request, _('The payment term has been changed.'))
|
||||||
self.order.log_action('pretix.event.order.expirychanged', user=self.request.user, data={
|
self.order.log_action('pretix.event.order.expirychanged', user=self.request.user, data={
|
||||||
'expires': self.order.expires
|
'expires': self.order.expires,
|
||||||
|
'state_change': False
|
||||||
})
|
})
|
||||||
self.form.save()
|
self.form.save()
|
||||||
else:
|
else:
|
||||||
@@ -460,8 +456,11 @@ class OrderExtend(OrderView):
|
|||||||
is_available = self.order._is_still_available(now_dt)
|
is_available = self.order._is_still_available(now_dt)
|
||||||
if is_available is True:
|
if is_available is True:
|
||||||
self.form.save()
|
self.form.save()
|
||||||
|
self.order.status = Order.STATUS_PENDING
|
||||||
|
self.order.save()
|
||||||
self.order.log_action('pretix.event.order.expirychanged', user=self.request.user, data={
|
self.order.log_action('pretix.event.order.expirychanged', user=self.request.user, data={
|
||||||
'expires': self.order.expires
|
'expires': self.order.expires,
|
||||||
|
'state_change': True
|
||||||
})
|
})
|
||||||
messages.success(self.request, _('The payment term has been changed.'))
|
messages.success(self.request, _('The payment term has been changed.'))
|
||||||
else:
|
else:
|
||||||
@@ -473,10 +472,13 @@ class OrderExtend(OrderView):
|
|||||||
else:
|
else:
|
||||||
return self.get(*args, **kwargs)
|
return self.get(*args, **kwargs)
|
||||||
|
|
||||||
def get(self, *args, **kwargs):
|
def dispatch(self, request, *args, **kwargs):
|
||||||
if self.order.status != Order.STATUS_PENDING:
|
if self.order.status not in (Order.STATUS_PENDING, Order.STATUS_EXPIRED):
|
||||||
messages.error(self.request, _('This action is only allowed for pending orders.'))
|
messages.error(self.request, _('This action is only allowed for pending orders.'))
|
||||||
return self._redirect_back()
|
return self._redirect_back()
|
||||||
|
return super().dispatch(request, *kwargs, **kwargs)
|
||||||
|
|
||||||
|
def get(self, *args, **kwargs):
|
||||||
return render(self.request, 'pretixcontrol/order/extend.html', {
|
return render(self.request, 'pretixcontrol/order/extend.html', {
|
||||||
'order': self.order,
|
'order': self.order,
|
||||||
'form': self.form,
|
'form': self.form,
|
||||||
|
|||||||
@@ -447,11 +447,11 @@ def test_order_extend_not_expired(client, env):
|
|||||||
|
|
||||||
|
|
||||||
@pytest.mark.django_db
|
@pytest.mark.django_db
|
||||||
def test_order_extend_expired_quota_left(client, env):
|
def test_order_extend_overdue_quota_empty(client, env):
|
||||||
o = Order.objects.get(id=env[2].id)
|
o = Order.objects.get(id=env[2].id)
|
||||||
o.expires = now() - timedelta(days=5)
|
o.expires = now() - timedelta(days=5)
|
||||||
o.save()
|
o.save()
|
||||||
q = Quota.objects.create(event=env[0], size=3)
|
q = Quota.objects.create(event=env[0], size=0)
|
||||||
q.items.add(env[3])
|
q.items.add(env[3])
|
||||||
newdate = (now() + timedelta(days=20)).strftime("%Y-%m-%d %H:%M:%S")
|
newdate = (now() + timedelta(days=20)).strftime("%Y-%m-%d %H:%M:%S")
|
||||||
client.login(email='dummy@dummy.dummy', password='dummy')
|
client.login(email='dummy@dummy.dummy', password='dummy')
|
||||||
@@ -463,10 +463,30 @@ def test_order_extend_expired_quota_left(client, env):
|
|||||||
assert o.expires.strftime("%Y-%m-%d %H:%M:%S") == newdate
|
assert o.expires.strftime("%Y-%m-%d %H:%M:%S") == newdate
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.django_db
|
||||||
|
def test_order_extend_expired_quota_left(client, env):
|
||||||
|
o = Order.objects.get(id=env[2].id)
|
||||||
|
o.expires = now() - timedelta(days=5)
|
||||||
|
o.status = Order.STATUS_EXPIRED
|
||||||
|
o.save()
|
||||||
|
q = Quota.objects.create(event=env[0], size=3)
|
||||||
|
q.items.add(env[3])
|
||||||
|
newdate = (now() + timedelta(days=20)).strftime("%Y-%m-%d %H:%M:%S")
|
||||||
|
client.login(email='dummy@dummy.dummy', password='dummy')
|
||||||
|
response = client.post('/control/event/dummy/dummy/orders/FOO/extend', {
|
||||||
|
'expires': newdate
|
||||||
|
}, follow=True)
|
||||||
|
assert 'alert-success' in response.rendered_content
|
||||||
|
o = Order.objects.get(id=env[2].id)
|
||||||
|
assert o.expires.strftime("%Y-%m-%d %H:%M:%S") == newdate
|
||||||
|
assert o.status == Order.STATUS_PENDING
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.django_db
|
@pytest.mark.django_db
|
||||||
def test_order_extend_expired_quota_empty(client, env):
|
def test_order_extend_expired_quota_empty(client, env):
|
||||||
o = Order.objects.get(id=env[2].id)
|
o = Order.objects.get(id=env[2].id)
|
||||||
o.expires = now() - timedelta(days=5)
|
o.expires = now() - timedelta(days=5)
|
||||||
|
o.status = Order.STATUS_EXPIRED
|
||||||
olddate = o.expires
|
olddate = o.expires
|
||||||
o.save()
|
o.save()
|
||||||
q = Quota.objects.create(event=env[0], size=0)
|
q = Quota.objects.create(event=env[0], size=0)
|
||||||
@@ -479,6 +499,34 @@ def test_order_extend_expired_quota_empty(client, env):
|
|||||||
assert 'alert-danger' in response.rendered_content
|
assert 'alert-danger' in response.rendered_content
|
||||||
o = Order.objects.get(id=env[2].id)
|
o = Order.objects.get(id=env[2].id)
|
||||||
assert o.expires.strftime("%Y-%m-%d %H:%M:%S") == olddate.strftime("%Y-%m-%d %H:%M:%S")
|
assert o.expires.strftime("%Y-%m-%d %H:%M:%S") == olddate.strftime("%Y-%m-%d %H:%M:%S")
|
||||||
|
assert o.status == Order.STATUS_EXPIRED
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.django_db
|
||||||
|
def test_order_extend_expired_quota_partial(client, env):
|
||||||
|
o = Order.objects.get(id=env[2].id)
|
||||||
|
OrderPosition.objects.create(
|
||||||
|
order=o,
|
||||||
|
item=env[3],
|
||||||
|
variation=None,
|
||||||
|
price=Decimal("14"),
|
||||||
|
attendee_name="Peter"
|
||||||
|
)
|
||||||
|
o.expires = now() - timedelta(days=5)
|
||||||
|
o.status = Order.STATUS_EXPIRED
|
||||||
|
olddate = o.expires
|
||||||
|
o.save()
|
||||||
|
q = Quota.objects.create(event=env[0], size=1)
|
||||||
|
q.items.add(env[3])
|
||||||
|
newdate = (now() + timedelta(days=20)).strftime("%Y-%m-%d %H:%M:%S")
|
||||||
|
client.login(email='dummy@dummy.dummy', password='dummy')
|
||||||
|
response = client.post('/control/event/dummy/dummy/orders/FOO/extend', {
|
||||||
|
'expires': newdate
|
||||||
|
}, follow=True)
|
||||||
|
assert 'alert-danger' in response.rendered_content
|
||||||
|
o = Order.objects.get(id=env[2].id)
|
||||||
|
assert o.expires.strftime("%Y-%m-%d %H:%M:%S") == olddate.strftime("%Y-%m-%d %H:%M:%S")
|
||||||
|
assert o.status == Order.STATUS_EXPIRED
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.django_db
|
@pytest.mark.django_db
|
||||||
|
|||||||
Reference in New Issue
Block a user