forked from CGM_Public/pretix_original
Do not issue invoices for free payments
This commit is contained in:
@@ -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))
|
||||||
|
|
||||||
|
|||||||
@@ -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
|
||||||
|
|
||||||
|
|||||||
@@ -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,
|
||||||
|
|||||||
@@ -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"""))
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -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,
|
||||||
|
|||||||
@@ -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"
|
||||||
|
|||||||
@@ -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.'))
|
||||||
|
|||||||
@@ -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 %}
|
||||||
|
|||||||
@@ -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.'))
|
||||||
|
|||||||
Reference in New Issue
Block a user