Provide support for manipulting order status

This commit is contained in:
Raphael Michel
2015-03-20 23:53:41 +01:00
parent 5664177bbb
commit a0b1a2e11b
8 changed files with 171 additions and 7 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', '0021_auto_20150320_1622'),
]
operations = [
migrations.AddField(
model_name='order',
name='payment_manual',
field=models.BooleanField(verbose_name='Payment state was manually modified', default=False),
),
migrations.AlterField(
model_name='order',
name='status',
field=models.CharField(verbose_name='Status', max_length=3, choices=[('n', 'pending'), ('p', 'paid'), ('e', 'expired'), ('c', 'cancelled'), ('r', 'refunded')]),
),
]

View File

@@ -1537,6 +1537,10 @@ class Order(Versionable):
verbose_name=_("Payment information"),
null=True, blank=True
)
payment_manual = models.BooleanField(
verbose_name=_("Payment state was manually modified"),
default=False
)
total = models.DecimalField(
decimal_places=2, max_digits=10,
verbose_name=_("Total amount")
@@ -1590,7 +1594,7 @@ class Order(Versionable):
return True
return False # nothing there to modify
def mark_paid(self, provider, info, date=None):
def mark_paid(self, provider=None, info=None, date=None, manual=None):
"""
Mark this order as paid. This clones the order object, sets the payment provider,
info and date and returns the cloned order object.
@@ -1604,9 +1608,11 @@ class Order(Versionable):
:type date: datetime
"""
order = self.clone()
order.payment_provider = provider
order.payment_info = info
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()
return order

View File

@@ -47,3 +47,10 @@ nav.navbar {
}
}
}
.btn-toolbar {
margin-bottom: 20px;
}
.container-fluid > .alert:first-child {
margin-top: 20px;
}

View File

@@ -74,6 +74,13 @@
</nav>
<div id="page-wrapper">
<div class="container-fluid">
{% if messages %}
{% for message in messages %}
<div class="alert {{ message.tags }}">
{{ message }}
</div>
{% endfor %}
{% endif %}
{% block content %}
{% endblock %}

View File

@@ -0,0 +1,32 @@
{% extends "pretixcontrol/event/base.html" %}
{% load i18n %}
{% block title %}
{% trans "Cancel order" %}
{% endblock %}
{% block content %}
<h1>
{% trans "Cancel order" %}
</h1>
<p>{% blocktrans trimmed %}
Do you really want to cancel this order? You cannot revert this action.
{% endblocktrans %}</p>
<form method="post" href="">
{% csrf_token %}
<input type="hidden" name="status" value="c" />
<div class="row checkout-button-row">
<div class="col-md-4">
<a class="btn btn-block btn-default btn-lg"
href="{% url "control:event.order" event=request.event.slug organizer=request.event.organizer.slug code=order.code %}">
{% trans "No, take me back" %}
</a>
</div>
<div class="col-md-4 col-md-offset-4">
<button class="btn btn-block btn-danger btn-lg" type="submit">
{% trans "Yes, cancel order" %}
</button>
</div>
<div class="clearfix"></div>
</div>
</form>
{% endblock %}

View File

@@ -12,6 +12,27 @@
{% endblocktrans %}
{% include "pretixcontrol/orders/fragment_order_status.html" with order=order class="pull-right" %}
</h1>
{% if order.status == 'n' or order.status == 'p' %}
<form action="{% url "control:event.order.transition" event=request.event.slug organizer=request.event.organizer.slug code=order.code %}"
method="post">
{% csrf_token %}
<div class="btn-toolbar" role="toolbar">
<div class="btn-group" role="group">
{% if order.status == 'n' %}
<button name="status" value="p" class="btn btn-default">{% trans "Mark as paid" %}</button>
<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" %}
</a>
{% elif order.status == 'p' %}
<button name="status" value="n" class="btn btn-default">{% trans "Mark as not paid" %}</button>
<a href="{% url "control:event.order.transition" event=request.event.slug organizer=request.event.organizer.slug code=order.code %}?status=r" class="btn btn-default">
{% trans "Refund order" %}
</a>
{% endif %}
</div>
</div>
</form>
{% endif %}
<div class="panel panel-primary items">
<div class="panel-heading">
<h3 class="panel-title">
@@ -86,6 +107,11 @@
</h3>
</div>
<div class="panel-body">
{% if order.payment_manual %}
<div class="alert alert-info">
{% trans "The payment state of this order was manually modified." %}
</div>
{% endif %}
{{ payment }}
{% if order.status == 'n' %}
<p>{% blocktrans trimmed with date=order.expires %}

View File

@@ -46,6 +46,8 @@ urlpatterns = [
url(r'^quotas/(?P<quota>[0-9a-f-]+)/delete$', item.QuotaDelete.as_view(),
name='event.items.quotas.delete'),
url(r'^quotas/add$', item.QuotaCreate.as_view(), name='event.items.quotas.add'),
url(r'^orders/(?P<code>[0-9A-Z]+)/transition$', orders.OrderTransition.as_view(),
name='event.order.transition'),
url(r'^orders/(?P<code>[0-9A-Z]+)/$', orders.OrderDetail.as_view(), name='event.order'),
url(r'^orders/$', orders.OrderList.as_view(), name='event.orders'),
])),

View File

@@ -1,5 +1,10 @@
from itertools import groupby
from django.contrib import messages
from django.core.urlresolvers import reverse
from django.db.models import Q
from django.utils.translation import ugettext_lazy as _
from django.http import HttpResponse
from django.shortcuts import redirect, render
from django.utils.functional import cached_property
from django.views.generic import ListView, DetailView
@@ -21,11 +26,9 @@ class OrderList(EventPermissionRequiredMixin, ListView):
).select_related("user")
class OrderDetail(EventPermissionRequiredMixin, DetailView):
model = Order
class OrderView(DetailView):
context_object_name = 'order'
template_name = 'pretixcontrol/order/index.html'
permission = 'can_view_orders'
model = Order
def get_object(self, queryset=None):
return Order.objects.current.get(
@@ -33,6 +36,15 @@ class OrderDetail(EventPermissionRequiredMixin, DetailView):
code=self.kwargs['code'].upper()
)
@cached_property
def order(self):
return self.get_object()
class OrderDetail(EventPermissionRequiredMixin, OrderView):
template_name = 'pretixcontrol/order/index.html'
permission = 'can_view_orders'
@cached_property
def payment_provider(self):
responses = register_payment_providers.send(self.request.event)
@@ -85,3 +97,51 @@ class OrderDetail(EventPermissionRequiredMixin, DetailView):
'total': self.object.total,
'payment_fee': self.object.payment_fee,
}
class OrderTransition(EventPermissionRequiredMixin, OrderView):
permission = 'can_view_orders'
def post(self, *args, **kwargs):
to = self.request.POST.get('status', '')
if self.order.status == 'n' and to == 'p':
self.order.mark_paid(manual=True)
messages.success(self.request, _('The order has been marked as paid.'))
elif self.order.status == 'n' and to == 'c':
order = self.order.clone()
order.status = Order.STATUS_CANCELLED
order.save()
messages.success(self.request, _('The order has been cancelled.'))
elif self.order.status == 'p' and to == 'n':
order = self.order.clone()
order.status = Order.STATUS_PENDING
order.payment_manual = True
order.save()
messages.success(self.request, _('The order has been marked as not paid.'))
return redirect(reverse(
'control:event.order',
kwargs={
'event': self.request.event.slug,
'organizer': self.request.event.organizer.slug,
'code': self.order.code,
}
))
def get(self, *args, **kwargs):
to = self.request.GET.get('status', '')
if self.order.status == 'n' and to == 'c':
return render(self.request, 'pretixcontrol/order/cancel.html', {
'order': self.order,
})
elif self.order.status == 'p' and to == 'r':
messages.error(self.request, _('Refunding orders is not yet implemented.'))
return redirect(reverse(
'control:event.order',
kwargs={
'event': self.request.event.slug,
'organizer': self.request.event.organizer.slug,
'code': self.order.code,
}
))
else:
return HttpResponse(status=405)