diff --git a/doc/development/api/general.rst b/doc/development/api/general.rst index 3023e78e71..3526f866f6 100644 --- a/doc/development/api/general.rst +++ b/doc/development/api/general.rst @@ -19,13 +19,13 @@ Order events There are multiple signals that will be sent out in the ordering cycle: .. automodule:: pretix.base.signals - :members: validate_cart, order_paid, order_placed + :members: validate_cart, fee_calculation_for_cart, order_fee_calculation, order_paid, order_placed Frontend -------- .. automodule:: pretix.presale.signals - :members: html_head, html_footer, footer_links, front_page_top, front_page_bottom, contact_form_fields, question_form_fields, checkout_confirm_messages + :members: html_head, html_footer, footer_links, front_page_top, front_page_bottom, contact_form_fields, question_form_fields, checkout_confirm_messages, checkout_confirm_page_content .. automodule:: pretix.presale.signals diff --git a/src/pretix/base/services/cart.py b/src/pretix/base/services/cart.py index c15f5115f5..a66994345a 100644 --- a/src/pretix/base/services/cart.py +++ b/src/pretix/base/services/cart.py @@ -20,6 +20,7 @@ from pretix.base.services.async import ProfiledTask from pretix.base.services.locking import LockTimeoutException from pretix.base.services.pricing import get_price from pretix.celery_app import app +from pretix.presale.signals import fee_calculation_for_cart class CartError(LazyLocaleException): @@ -627,7 +628,7 @@ def update_tax_rates(event: Event, cart_id: str, invoice_address: InvoiceAddress return totaldiff -def get_fees(event, total, invoice_address, provider): +def get_fees(event, request, total, invoice_address, provider): fees = [] if total == 0: @@ -643,7 +644,7 @@ def get_fees(event, total, invoice_address, provider): if payment_fee_tax_rule.tax_applicable(invoice_address): payment_fee_tax = payment_fee_tax_rule.tax(payment_fee, base_price_is='gross') fees.append(OrderFee( - fee_type="PAYMENT", + fee_type=OrderFee.FEE_TYPE_PAYMENT, value=payment_fee, tax_rate=payment_fee_tax.rate, tax_value=payment_fee_tax.tax, @@ -651,13 +652,16 @@ def get_fees(event, total, invoice_address, provider): )) else: fees.append(OrderFee( - fee_type="PAYMENT", + fee_type=OrderFee.FEE_TYPE_PAYMENT, value=payment_fee, tax_rate=Decimal('0.00'), tax_value=Decimal('0.00'), tax_rule=payment_fee_tax_rule )) + for recv, resp in fee_calculation_for_cart.send(sender=event, request=request, invoice_address=invoice_address): + fees += resp + return fees diff --git a/src/pretix/base/services/orders.py b/src/pretix/base/services/orders.py index ff2ec9885e..b0691b62a8 100644 --- a/src/pretix/base/services/orders.py +++ b/src/pretix/base/services/orders.py @@ -34,7 +34,9 @@ from pretix.base.services.invoices import ( from pretix.base.services.locking import LockTimeoutException from pretix.base.services.mail import SendMailException from pretix.base.services.pricing import get_price -from pretix.base.signals import order_paid, order_placed, periodic_task +from pretix.base.signals import ( + order_fee_calculation, order_paid, order_placed, periodic_task, +) from pretix.celery_app import app from pretix.multidomain.urlreverse import build_absolute_uri @@ -342,7 +344,8 @@ def _check_positions(event: Event, now_dt: datetime, positions: List[CartPositio raise OrderError(err, errargs) -def _get_fees(positions: List[CartPosition], payment_provider: BasePaymentProvider): +def _get_fees(positions: List[CartPosition], payment_provider: BasePaymentProvider, address: InvoiceAddress, + meta_info: dict, event: Event): fees = [] total = sum([c.price for c in positions]) payment_fee = payment_provider.calculate_fee(total) @@ -350,15 +353,18 @@ def _get_fees(positions: List[CartPosition], payment_provider: BasePaymentProvid fees.append(OrderFee(fee_type=OrderFee.FEE_TYPE_PAYMENT, value=payment_fee, internal_type=payment_provider.identifier)) + for recv, resp in order_fee_calculation.send(sender=event, invoice_address=address, + meta_info=meta_info, posiitons=positions): + fees += resp return fees def _create_order(event: Event, email: str, positions: List[CartPosition], now_dt: datetime, - payment_provider: BasePaymentProvider, locale: str=None, address: int=None, + payment_provider: BasePaymentProvider, locale: str=None, address: InvoiceAddress=None, meta_info: dict=None): from datetime import time - fees = _get_fees(positions, payment_provider) + fees = _get_fees(positions, payment_provider, address, meta_info, event) total = sum([c.price for c in positions]) + sum([c.value for c in fees]) tz = pytz.timezone(event.settings.timezone) diff --git a/src/pretix/base/signals.py b/src/pretix/base/signals.py index b6a0bb4718..69e56c0cc4 100644 --- a/src/pretix/base/signals.py +++ b/src/pretix/base/signals.py @@ -209,3 +209,16 @@ register_global_settings = django.dispatch.Signal() All plugins that are installed may send fields for the global settings form, as an OrderedDict of (setting name, form field). """ + +order_fee_calculation = EventPluginSignal( + providing_args=['request'] +) +""" +This signals allows you to add fees to an order while it is being created. You are expected to +return a list of ``OrderFee`` objects that are not yet saved to the database +(because there is no order yet). + +As with all plugin signals, the ``sender`` keyword argument will contain the event. A ``positions`` +argument will contain the cart positions and ``invoice_address`` the invoice address (useful for +tax calculation). The argument ``meta_info`` contains the order's meta dictionary. +""" diff --git a/src/pretix/presale/signals.py b/src/pretix/presale/signals.py index 9bff40843c..221cdc6b31 100644 --- a/src/pretix/presale/signals.py +++ b/src/pretix/presale/signals.py @@ -68,7 +68,6 @@ You will recieve the request triggering the order creation as the ``request`` ke As with all event-plugin signals, the ``sender`` keyword argument will contain the event. """ - checkout_confirm_page_content = EventPluginSignal( providing_args=['request'] ) @@ -80,6 +79,18 @@ As with all plugin signals, the ``sender`` keyword argument will contain the eve argument will contain the request object. """ +fee_calculation_for_cart = EventPluginSignal( + providing_args=['request'] +) +""" +This signals allows you to add fees to a cart. You are expected to return a list of ``OrderFee`` +objects that are not yet saved to the database (because there is no order yet). + +As with all plugin signals, the ``sender`` keyword argument will contain the event. A ``request`` +argument will contain the request object and ``invoice_address`` the invoice address (useful for +tax calculation). +""" + contact_form_fields = EventPluginSignal( providing_args=[] ) diff --git a/src/pretix/presale/templates/pretixpresale/event/fragment_cart.html b/src/pretix/presale/templates/pretixpresale/event/fragment_cart.html index 6ef31db450..4919166253 100644 --- a/src/pretix/presale/templates/pretixpresale/event/fragment_cart.html +++ b/src/pretix/presale/templates/pretixpresale/event/fragment_cart.html @@ -159,7 +159,7 @@ {% for fee in cart.fees %}
- {% trans "Payment method fee" %} + {{ fee.get_fee_type_display }}
{% if event.settings.display_net_prices %} diff --git a/src/pretix/presale/views/__init__.py b/src/pretix/presale/views/__init__.py index 4752a5f027..cc0dbc016e 100644 --- a/src/pretix/presale/views/__init__.py +++ b/src/pretix/presale/views/__init__.py @@ -110,7 +110,7 @@ class CartMixin: except InvoiceAddress.DoesNotExist: pass - fees = get_fees(self.request.event, total, ia, self.request.session.get('payment')) + fees = get_fees(self.request.event, self.request, total, ia, self.request.session.get('payment')) total += sum([f.value for f in fees]) net_total += sum([f.net_value for f in fees])