Do not issue invoices for free payments

This commit is contained in:
Raphael Michel
2016-08-05 11:06:22 +02:00
parent f93b2211a6
commit a61792ed4e
9 changed files with 78 additions and 26 deletions

View File

@@ -431,7 +431,7 @@ class FreeOrderProvider(BasePaymentProvider):
def payment_perform(self, request: HttpRequest, order: Order): def payment_perform(self, request: HttpRequest, order: Order):
from pretix.base.services.orders import mark_order_paid from pretix.base.services.orders import mark_order_paid
try: try:
mark_order_paid(order, 'free') mark_order_paid(order, 'free', send_mail=False)
except Quota.QuotaExceededException as e: except Quota.QuotaExceededException as e:
messages.error(request, str(e)) messages.error(request, str(e))

View File

@@ -325,6 +325,12 @@ def invoice_pdf(invoice: int):
return i.file.name return i.file.name
def invoice_qualified(order: Order):
if order.total == Decimal('0.00'):
return False
return True
if settings.HAS_CELERY: if settings.HAS_CELERY:
from pretix.celery import app from pretix.celery import app

View File

@@ -1,4 +1,5 @@
from datetime import datetime, timedelta from datetime import datetime, timedelta
from decimal import Decimal
from django.conf import settings from django.conf import settings
from django.db import transaction from django.db import transaction
@@ -16,7 +17,7 @@ from pretix.base.models import (
from pretix.base.models.orders import InvoiceAddress from pretix.base.models.orders import InvoiceAddress
from pretix.base.payment import BasePaymentProvider from pretix.base.payment import BasePaymentProvider
from pretix.base.services.invoices import ( from pretix.base.services.invoices import (
generate_cancellation, generate_invoice, generate_cancellation, generate_invoice, invoice_qualified,
) )
from pretix.base.services.mail import mail from pretix.base.services.mail import mail
from pretix.base.signals import ( from pretix.base.signals import (
@@ -46,7 +47,7 @@ error_messages = {
def mark_order_paid(order: Order, provider: str=None, info: str=None, date: datetime=None, manual: bool=None, def mark_order_paid(order: Order, provider: str=None, info: str=None, date: datetime=None, manual: bool=None,
force: bool=False, user: User=None) -> Order: force: bool=False, send_mail: bool=True, user: User=None) -> Order:
""" """
Marks an order as paid. This sets the payment provider, info and date and returns Marks an order as paid. This sets the payment provider, info and date and returns
the order object. the order object.
@@ -61,6 +62,8 @@ def mark_order_paid(order: Order, provider: str=None, info: str=None, date: date
:param force: Whether this payment should be marked as paid even if no remaining :param force: Whether this payment should be marked as paid even if no remaining
quota is available (default: ``False``). quota is available (default: ``False``).
:type force: boolean :type force: boolean
:param send_mail: Whether an email should be sent to the user about this event (default: ``True``).
:type send_mail: boolean
:param user: The user that performed the change :param user: The user that performed the change
:raises Quota.QuotaExceededException: if the quota is exceeded and ``force`` is ``False`` :raises Quota.QuotaExceededException: if the quota is exceeded and ``force`` is ``False``
""" """
@@ -85,20 +88,21 @@ def mark_order_paid(order: Order, provider: str=None, info: str=None, date: date
}, user=user) }, user=user)
order_paid.send(order.event, order=order) order_paid.send(order.event, order=order)
with language(order.locale): if send_mail:
mail( with language(order.locale):
order.email, _('Payment received for your order: %(code)s') % {'code': order.code}, mail(
order.event.settings.mail_text_order_paid, order.email, _('Payment received for your order: %(code)s') % {'code': order.code},
{ order.event.settings.mail_text_order_paid,
'event': order.event.name, {
'url': build_absolute_uri(order.event, 'presale:event.order', kwargs={ 'event': order.event.name,
'order': order.code, 'url': build_absolute_uri(order.event, 'presale:event.order', kwargs={
'secret': order.secret 'order': order.code,
}), 'secret': order.secret
'downloads': order.event.settings.get('ticket_download', as_type=bool) }),
}, 'downloads': order.event.settings.get('ticket_download', as_type=bool)
order.event, locale=order.locale },
) order.event, locale=order.locale
)
return order return order
@@ -289,13 +293,17 @@ def _perform_order(event: str, payment_provider: str, position_ids: List[str],
except InvoiceAddress.DoesNotExist: except InvoiceAddress.DoesNotExist:
pass pass
if event.settings.get('invoice_generate') == 'True': if event.settings.get('invoice_generate') == 'True' and invoice_qualified(order):
generate_invoice(order) generate_invoice(order)
with language(order.locale): with language(order.locale):
if order.total == Decimal('0.00'):
mailtext = event.settings.mail_text_order_free
else:
mailtext = event.settings.mail_text_order_placed
mail( mail(
order.email, _('Your order: %(code)s') % {'code': order.code}, order.email, _('Your order: %(code)s') % {'code': order.code},
event.settings.mail_text_order_placed, mailtext,
{ {
'total': LazyNumber(order.total), 'total': LazyNumber(order.total),
'currency': event.currency, 'currency': event.currency,

View File

@@ -147,6 +147,19 @@ to your order for {event}.
You can change your order details and view the status of your order at You can change your order details and view the status of your order at
{url} {url}
Best regards,
Your {event} team"""))
},
'mail_text_order_free': {
'type': LazyI18nString,
'default': LazyI18nString.from_gettext(ugettext_noop("""Hello,
we successfully received your order for {event}. As you only ordered
free products, no payment is required.
You can change your order details and view the status of your order at
{url}
Best regards, Best regards,
Your {event} team""")) Your {event} team"""))
}, },

View File

@@ -298,6 +298,12 @@ class MailSettingsForm(SettingsForm):
widget=I18nTextarea, widget=I18nTextarea,
help_text=_("Available placeholders: {event}, {url}") help_text=_("Available placeholders: {event}, {url}")
) )
mail_text_order_free = I18nFormField(
label=_("Free order"),
required=False,
widget=I18nTextarea,
help_text=_("Available placeholders: {event}, {url}")
)
mail_text_resend_link = I18nFormField( mail_text_resend_link = I18nFormField(
label=_("Resend link"), label=_("Resend link"),
required=False, required=False,

View File

@@ -110,7 +110,7 @@
{% endif %} {% endif %}
{% endfor %} {% endfor %}
</dd> </dd>
{% elif request.event.settings.invoice_generate == 'admin' or request.event.settings.invoice_generate == 'user' %} {% elif can_generate_invoice %}
<dt>{% trans "Invoices" %}</dt> <dt>{% trans "Invoices" %}</dt>
<dd> <dd>
<form class="form-inline helper-display-inline" method="post" <form class="form-inline helper-display-inline" method="post"

View File

@@ -17,7 +17,9 @@ from pretix.base.models import (
) )
from pretix.base.services import tickets from pretix.base.services import tickets
from pretix.base.services.export import export from pretix.base.services.export import export
from pretix.base.services.invoices import generate_invoice, invoice_pdf from pretix.base.services.invoices import (
generate_invoice, invoice_pdf, invoice_qualified,
)
from pretix.base.services.mail import mail from pretix.base.services.mail import mail
from pretix.base.services.orders import cancel_order, mark_order_paid from pretix.base.services.orders import cancel_order, mark_order_paid
from pretix.base.services.stats import order_overview from pretix.base.services.stats import order_overview
@@ -75,6 +77,14 @@ class OrderView(EventPermissionRequiredMixin, DetailView):
def order(self): def order(self):
return self.get_object() return self.get_object()
def get_context_data(self, **kwargs):
ctx = super().get_context_data(**kwargs)
ctx['can_generate_invoice'] = invoice_qualified(self.order) and (
self.request.event.settings.invoice_generate == 'admin' or
self.request.event.settings.invoice_generate == 'user'
)
return ctx
@cached_property @cached_property
def payment_provider(self): def payment_provider(self):
responses = register_payment_providers.send(self.request.event) responses = register_payment_providers.send(self.request.event)
@@ -212,7 +222,8 @@ class OrderInvoiceCreate(OrderView):
permission = 'can_change_orders' permission = 'can_change_orders'
def post(self, *args, **kwargs): def post(self, *args, **kwargs):
if self.request.event.settings.get('invoice_generate') not in ('admin', 'user'): if self.request.event.settings.get('invoice_generate') not in ('admin', 'user') or not invoice_qualified(
self.order):
messages.error(self.request, _('You cannot generate an invoice for this order.')) messages.error(self.request, _('You cannot generate an invoice for this order.'))
elif self.order.invoices.exists(): elif self.order.invoices.exists():
messages.error(self.request, _('An invoice for this order already exists.')) messages.error(self.request, _('An invoice for this order already exists.'))

View File

@@ -12,6 +12,8 @@
<h2>{% trans "Thank you!" %}</h2> <h2>{% trans "Thank you!" %}</h2>
{% if order.status != 'p' %} {% if order.status != 'p' %}
<p>{% trans "Your order has been placed successfully. See below for details." %}</p> <p>{% trans "Your order has been placed successfully. See below for details." %}</p>
{% elif order.total == 0 %}
<p>{% trans "Your order has been processed successfully! See below for details." %}</p>
{% else %} {% else %}
<p>{% trans "We successfully received your payment. See below for details." %}</p> <p>{% trans "We successfully received your payment. See below for details." %}</p>
{% endif %} {% endif %}
@@ -118,7 +120,7 @@
</div> </div>
</div> </div>
</div> </div>
{% elif request.event.settings.invoice_generate == 'user' %} {% elif can_generate_invoice %}
<div class="col-xs-12 {% if request.event.settings.invoice_address_asked %}col-md-6{% endif %}"> <div class="col-xs-12 {% if request.event.settings.invoice_address_asked %}col-md-6{% endif %}">
<div class="panel panel-primary"> <div class="panel panel-primary">
<div class="panel-heading"> <div class="panel-heading">
@@ -139,7 +141,7 @@
</div> </div>
{% endif %} {% endif %}
{% if request.event.settings.invoice_address_asked %} {% if request.event.settings.invoice_address_asked %}
<div class="col-xs-12 {% if invoices or request.event.settings.invoice_generate == 'user' %}col-md-6{% endif %}"> <div class="col-xs-12 {% if invoices or can_generate_invoice %}col-md-6{% endif %}">
<div class="panel panel-primary"> <div class="panel panel-primary">
<div class="panel-heading"> <div class="panel-heading">
{% if order.can_modify_answers %} {% if order.can_modify_answers %}

View File

@@ -13,7 +13,9 @@ from pretix.base.models import (
CachedFile, CachedTicket, Invoice, Order, OrderPosition, CachedFile, CachedTicket, Invoice, Order, OrderPosition,
) )
from pretix.base.models.orders import InvoiceAddress from pretix.base.models.orders import InvoiceAddress
from pretix.base.services.invoices import generate_invoice, invoice_pdf from pretix.base.services.invoices import (
generate_invoice, invoice_pdf, invoice_qualified,
)
from pretix.base.services.orders import OrderError, cancel_order from pretix.base.services.orders import OrderError, cancel_order
from pretix.base.services.tickets import generate from pretix.base.services.tickets import generate
from pretix.base.signals import ( from pretix.base.signals import (
@@ -91,6 +93,10 @@ class OrderDetails(EventViewMixin, OrderDetailMixin, CartMixin, TemplateView):
payment_fee=self.order.payment_fee, payment_fee_tax_rate=self.order.payment_fee_tax_rate payment_fee=self.order.payment_fee, payment_fee_tax_rate=self.order.payment_fee_tax_rate
) )
ctx['invoices'] = list(self.order.invoices.all()) ctx['invoices'] = list(self.order.invoices.all())
ctx['can_generate_invoice'] = invoice_qualified(self.order) and (
self.request.event.settings.invoice_generate == 'user'
)
if self.order.status == Order.STATUS_PENDING: if self.order.status == Order.STATUS_PENDING:
ctx['payment'] = self.payment_provider.order_pending_render(self.request, self.order) ctx['payment'] = self.payment_provider.order_pending_render(self.request, self.order)
ctx['can_retry'] = ( ctx['can_retry'] = (
@@ -155,7 +161,7 @@ class OrderInvoiceCreate(EventViewMixin, OrderDetailMixin, View):
return super().dispatch(request, *args, **kwargs) return super().dispatch(request, *args, **kwargs)
def post(self, request, *args, **kwargs): def post(self, request, *args, **kwargs):
if self.request.event.settings.get('invoice_generate') != 'user': if self.request.event.settings.get('invoice_generate') != 'user' or not invoice_qualified(self.order):
messages.error(self.request, _('You cannot generate an invoice for this order.')) messages.error(self.request, _('You cannot generate an invoice for this order.'))
elif self.order.invoices.exists(): elif self.order.invoices.exists():
messages.error(self.request, _('An invoice for this order already exists.')) messages.error(self.request, _('An invoice for this order already exists.'))