Offer download options per position, not per order

This commit is contained in:
Raphael Michel
2016-11-01 17:58:41 +01:00
parent 3344c02c80
commit ad35110166
25 changed files with 630 additions and 703 deletions

View File

@@ -23,7 +23,7 @@
</div>
<div class="panel-body">
{% include "pretixpresale/event/fragment_cart.html" with cart=cart event=request.event editable=False %}
<div class="row-fluid">
<div class="cart-row row">
<div class="col-md-6 col-xs-12">
<em id="cart-deadline" data-expires="{{ cart.first_expiry|date:"Y-m-d H:i:sO" }}">
{% if cart.minutes_left > 0 %}

View File

@@ -1,8 +1,8 @@
{% load i18n %}
{% load eventurl %}
{% for line in cart.positions %}
<div class="row-fluid cart-row">
<div class="col-md-4 col-xs-6">
<div class="row cart-row {% if download %}has-downloads{% endif %}">
<div class="product">
<strong>{{ line.item.name }}</strong>
{% if line.variation %}
{{ line.variation }}
@@ -10,63 +10,77 @@
{% if line.voucher %}
<br /><span class="fa fa-tags"></span> {% trans "Voucher code used:" %} {{ line.voucher.code }}
{% endif %}
{% if line.has_questions %}
<dl>
{% if line.item.admission and event.settings.attendee_names_asked%}
<dt>{% trans "Attendee name" %}</dt>
<dd>{% if line.attendee_name %}{{ line.attendee_name }}{% else %}<em>{% trans "not answered" %}</em>{% endif %}</dd>
{% endif %}
{% for q in line.questions %}
<dt>{{ q.question }}</dt>
<dd>{% if q.answer %}{{ q.answer|linebreaksbr }}{% else %}<em>{% trans "not answered" %}</em>{% endif %}</dd>
{% endfor %}
</dl>
{% endif %}
</div>
<div class="col-md-2 col-xs-6 count">
{% if editable %}
<form action="{% eventurl event "presale:event.cart.remove" %}"
method="post" data-asynctask>
{% csrf_token %}
{% if line.variation %}
<input type="hidden" name="variation_{{ line.item.id }}_{{ line.variation.id }}"
value="1" />
<input type="hidden" name="price_{{ line.item.id }}_{{ line.variation.id }}"
value="{{ line.price }}" />
{% else %}
<input type="hidden" name="item_{{ line.item.id }}"
value="1" />
<input type="hidden" name="price_{{ line.item.id }}"
value="{{ line.price }}" />
{% endif %}
<button class="btn btn-mini btn-link"><i class="fa fa-minus"></i></button>
</form>
{% endif %}
{{ line.count }}
{% if editable %}
<form action="{% eventurl event "presale:event.cart.add" %}"
method="post" data-asynctask>
{% csrf_token %}
{% if line.variation %}
<input type="hidden" name="variation_{{ line.item.id }}_{{ line.variation.id }}"
value="1" />
<input type="hidden" name="price_{{ line.item.id }}_{{ line.variation.id }}"
value="{{ line.price }}" />
{% else %}
<input type="hidden" name="item_{{ line.item.id }}"
value="1" />
<input type="hidden" name="price_{{ line.item.id }}"
value="{{ line.price }}" />
{% endif %}
<button class="btn btn-mini btn-link"><i class="fa fa-plus"></i></button>
</form>
{% if line.has_questions %}
<dl>
{% if line.item.admission and event.settings.attendee_names_asked%}
<dt>{% trans "Attendee name" %}</dt>
<dd>{% if line.attendee_name %}{{ line.attendee_name }}{% else %}<em>{% trans "not answered" %}</em>{% endif %}</dd>
{% endif %}
{% for q in line.questions %}
<dt>{{ q.question }}</dt>
<dd>{% if q.answer %}{{ q.answer|linebreaksbr }}{% else %}<em>{% trans "not answered" %}</em>{% endif %}</dd>
{% endfor %}
</dl>
{% endif %}
</div>
<div class="col-md-3 col-xs-6 price">
{{ event.currency }} {{ line.price|floatformat:2 }}
</div>
<div class="col-md-3 col-xs-6 price">
{% if download %}
<div class="download-desktop">
{% for b in download_buttons %}
<a href="{% eventurl event "presale:event.order.download" secret=order.secret order=order.code output=b.identifier position=line.id %}"
class="btn btn-default btn-sm">
<span class="fa fa-download"></span> {{ b.text }}
</a>
{% endfor %}
</div>
{% else %}
<div class="count">
{% if editable %}
<form action="{% eventurl event "presale:event.cart.remove" %}"
method="post" data-asynctask>
{% csrf_token %}
{% if line.variation %}
<input type="hidden" name="variation_{{ line.item.id }}_{{ line.variation.id }}"
value="1" />
<input type="hidden" name="price_{{ line.item.id }}_{{ line.variation.id }}"
value="{{ line.price }}" />
{% else %}
<input type="hidden" name="item_{{ line.item.id }}"
value="1" />
<input type="hidden" name="price_{{ line.item.id }}"
value="{{ line.price }}" />
{% endif %}
<button class="btn btn-mini btn-link"><i class="fa fa-minus"></i></button>
</form>
{% endif %}
{{ line.count }}
{% if editable %}
<form action="{% eventurl event "presale:event.cart.add" %}"
method="post" data-asynctask>
{% csrf_token %}
{% if line.variation %}
<input type="hidden" name="variation_{{ line.item.id }}_{{ line.variation.id }}"
value="1" />
<input type="hidden" name="price_{{ line.item.id }}_{{ line.variation.id }}"
value="{{ line.price }}" />
{% else %}
<input type="hidden" name="item_{{ line.item.id }}"
value="1" />
<input type="hidden" name="price_{{ line.item.id }}"
value="{{ line.price }}" />
{% endif %}
<button class="btn btn-mini btn-link"><i class="fa fa-plus"></i></button>
</form>
{% endif %}
</div>
<div class="singleprice price">
{{ event.currency }} {{ line.price|floatformat:2 }}
</div>
{% endif %}
<div class="totalprice price">
<strong>{{ event.currency }} {{ line.total|floatformat:2 }}</strong>
{% if line.tax_rate %}
<br /><small>{% blocktrans trimmed with rate=line.tax_rate %}
@@ -74,12 +88,22 @@
{% endblocktrans %}</small>
{% endif %}
</div>
{% if download %}
<div class="download-mobile">
{% for b in download_buttons %}
<a href="{% eventurl event "presale:event.order.download" secret=order.secret order=order.code output=b.identifier position=line.id %}"
class="btn btn-default btn-sm">
<span class="fa fa-download"></span> {{ b.text }}
</a>
{% endfor %}
</div>
{% endif %}
<div class="clearfix"></div>
</div>
{% endfor %}
{% if cart.payment_fee %}
{# TODO: Tax rate? #}
<div class="row-fluid cart-row">
<div class="row cart-row">
<div class="col-md-4 col-xs-6">
<strong>{% trans "Payment method fee" %}</strong>
</div>
@@ -95,7 +119,7 @@
<div class="clearfix"></div>
</div>
{% endif %}
<div class="row-fluid cart-row total">
<div class="row cart-row total">
<div class="col-md-4 col-xs-6">
<strong>{% trans "Total" %}</strong>
</div>

View File

@@ -15,7 +15,7 @@
</div>
<div class="panel-body">
{% include "pretixpresale/event/fragment_cart.html" with cart=cart event=request.event editable=True %}
<div class="row-fluid">
<div class="cart-row row">
<div class="col-md-6 col-xs-12">
<em id="cart-deadline" data-expires="{{ cart.first_expiry|date:"Y-m-d H:i:sO" }}">
{% if cart.minutes_left > 0 %}

View File

@@ -67,29 +67,16 @@
</div>
{% endif %}
{% if order.status == 'p' and event.settings.ticket_download %}
<div class="panel panel-primary">
<div class="panel-heading">
<h3 class="panel-title">{% trans "Ticket download" %}</h3>
</div>
<div class="panel-body">
{% if can_download %}
<p>
{% blocktrans trimmed %}
Please obtain your ticket below. Please have your ticket ready when entering the event.
{% endblocktrans %}
</p>
{% for b in download_buttons %}
<a href="{% eventurl event "presale:event.order.download" secret=order.secret order=order.code output=b.identifier %}"
class="btn btn-primary">
<span class="fa {{ b.icon }}"></span> {{ b.text }}
</a>
{% endfor %}
{% else %}
{% blocktrans trimmed with date=event.settings.ticket_download_date|date:"SHORT_DATE_FORMAT" %}
You will be able to download your tickets here starting on {{ date }}.
{% endblocktrans %}
{% endif %}
</div>
<div class="alert alert-info">
{% if can_download %}
{% blocktrans trimmed %}
You can download your tickets using the buttons below. Please have your ticket ready when entering the event.
{% endblocktrans %}
{% else %}
{% blocktrans trimmed with date=event.settings.ticket_download_date|date:"SHORT_DATE_FORMAT" %}
You will be able to download your tickets here starting on {{ date }}.
{% endblocktrans %}
{% endif %}
</div>
{% endif %}
<div class="panel panel-primary cart">
@@ -107,7 +94,7 @@
</h3>
</div>
<div class="panel-body">
{% include "pretixpresale/event/fragment_cart.html" with cart=cart event=request.event editable=False %}
{% include "pretixpresale/event/fragment_cart.html" with cart=cart event=request.event download=can_download editable=False %}
</div>
</div>
{% eventsignal event "pretix.presale.signals.order_info" order=order %}

View File

@@ -45,7 +45,7 @@ event_patterns = [
url(r'^order/(?P<order>[^/]+)/(?P<secret>[A-Za-z0-9]+)/pay/change',
pretix.presale.views.order.OrderPayChangeMethod.as_view(),
name='event.order.pay.change'),
url(r'^order/(?P<order>[^/]+)/(?P<secret>[A-Za-z0-9]+)/download/(?P<output>[^/]+)$',
url(r'^order/(?P<order>[^/]+)/(?P<secret>[A-Za-z0-9]+)/download/(?P<position>[0-9]+)/(?P<output>[^/]+)$',
pretix.presale.views.order.OrderDownload.as_view(),
name='event.order.download'),
url(r'^order/(?P<order>[^/]+)/(?P<secret>[A-Za-z0-9]+)/invoice/(?P<invoice>[^/]+)$',

View File

@@ -25,7 +25,7 @@ class CartMixin:
'item__questions', 'answers'
))
def get_cart(self, answers=False, queryset=None, payment_fee=None, payment_fee_tax_rate=None):
def get_cart(self, answers=False, queryset=None, payment_fee=None, payment_fee_tax_rate=None, downloads=False):
queryset = queryset or CartPosition.objects.filter(
cart_id=self.request.session.session_key, event=self.request.event
)
@@ -47,6 +47,8 @@ class CartMixin:
# We do this by list manipulations instead of a GROUP BY query, as
# Django is unable to join related models in a .values() query
def keyfunc(pos):
if downloads:
return pos.id, 0, 0, 0, 0
if answers and ((pos.item.admission and self.request.event.settings.attendee_names_asked)
or pos.item.questions.all()):
return pos.id, 0, 0, 0, 0

View File

@@ -79,8 +79,7 @@ class OrderDetails(EventViewMixin, OrderDetailMixin, CartMixin, TemplateView):
if not provider.is_enabled:
continue
buttons.append({
'icon': provider.download_button_icon or 'fa-download',
'text': provider.download_button_text or 'fa-download',
'text': provider.download_button_text or 'Download',
'identifier': provider.identifier,
})
return buttons
@@ -97,7 +96,7 @@ class OrderDetails(EventViewMixin, OrderDetailMixin, CartMixin, TemplateView):
)
ctx['download_buttons'] = self.download_buttons
ctx['cart'] = self.get_cart(
answers=True,
answers=True, downloads=ctx['can_download'],
queryset=OrderPosition.objects.filter(order=self.order),
payment_fee=self.order.payment_fee, payment_fee_tax_rate=self.order.payment_fee_tax_rate
)
@@ -478,6 +477,7 @@ class OrderCancelDo(EventViewMixin, OrderDetailMixin, AsyncAction, View):
class OrderDownload(EventViewMixin, OrderDetailMixin, View):
@cached_property
def output(self):
responses = register_ticket_outputs.send(self.request.event)
@@ -486,11 +486,18 @@ class OrderDownload(EventViewMixin, OrderDetailMixin, View):
if provider.identifier == self.kwargs.get('output'):
return provider
@cached_property
def order_position(self):
try:
return self.order.positions.get(pk=self.kwargs.get('position'))
except OrderPosition.DoesNotExist:
return None
def get(self, request, *args, **kwargs):
if not self.output or not self.output.is_enabled:
messages.error(request, _('You requested an invalid ticket output type.'))
return redirect(self.get_order_url())
if not self.order:
if not self.order or not self.order_position:
raise Http404(_('Unknown order code or not authorized to access this order.'))
if self.order.status != Order.STATUS_PAID:
messages.error(request, _('Order is not paid.'))
@@ -501,7 +508,9 @@ class OrderDownload(EventViewMixin, OrderDetailMixin, View):
messages.error(request, _('Ticket download is not (yet) enabled.'))
return redirect(self.get_order_url())
ct = CachedTicket.objects.get_or_create(order=self.order, provider=self.output.identifier)[0]
ct = CachedTicket.objects.get_or_create(
order_position=self.order_position, provider=self.output.identifier
)[0]
if not ct.cachedfile:
cf = CachedFile()
cf.date = now()
@@ -509,7 +518,7 @@ class OrderDownload(EventViewMixin, OrderDetailMixin, View):
cf.save()
ct.cachedfile = cf
ct.save()
generate.apply_async(args=(self.order.id, self.output.identifier))
generate.apply_async(args=(self.order_position.id, self.output.identifier))
return redirect(reverse('cachedfile.download', kwargs={'id': ct.cachedfile.id}))