mirror of
https://github.com/pretix/pretix.git
synced 2026-05-10 16:04:02 +00:00
Offer download options per position, not per order
This commit is contained in:
@@ -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 %}
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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 %}
|
||||
|
||||
@@ -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 %}
|
||||
|
||||
@@ -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>[^/]+)$',
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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}))
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user