From c820d742d414b970c4c928e7f1a9727ddc8366cf Mon Sep 17 00:00:00 2001 From: Raphael Michel Date: Mon, 3 Feb 2025 17:39:46 +0100 Subject: [PATCH] Generate invoice earlier in payment method change process (Z#23179304) (#4763) * Generate invoice earlier in payment method change process (Z##23179304) * Resolve review note --- src/pretix/base/services/orders.py | 24 ++++++++++++++++++++-- src/pretix/plugins/banktransfer/tasks.py | 5 +++-- src/pretix/presale/views/order.py | 26 ++++++++---------------- 3 files changed, 33 insertions(+), 22 deletions(-) diff --git a/src/pretix/base/services/orders.py b/src/pretix/base/services/orders.py index 9e12e9e30..456318398 100644 --- a/src/pretix/base/services/orders.py +++ b/src/pretix/base/services/orders.py @@ -3114,14 +3114,34 @@ def change_payment_provider(order: Order, payment_provider, amount=None, new_pay } ) + new_invoice_created = False if recreate_invoices: + # Lock to prevent duplicate invoice creation + order = Order.objects.select_for_update(of=OF_SELF).get(pk=order.pk) + i = order.invoices.filter(is_cancellation=False).last() - if i and order.total != oldtotal and not i.canceled: + has_active_invoice = i and not i.canceled + + if has_active_invoice and order.total != oldtotal: generate_cancellation(i) generate_invoice(order) + new_invoice_created = True + + elif (not has_active_invoice or order.invoice_dirty) and invoice_qualified(order): + if order.event.settings.get('invoice_generate') == 'True' or ( + order.event.settings.get('invoice_generate') == 'paid' and + new_payment.payment_provider.requires_invoice_immediately + ): + if has_active_invoice: + generate_cancellation(i) + i = generate_invoice(order) + new_invoice_created = True + order.log_action('pretix.event.order.invoice.generated', data={ + 'invoice': i.pk + }) order.create_transactions() - return old_fee, new_fee, fee, new_payment + return old_fee, new_fee, fee, new_payment, new_invoice_created @receiver(order_paid, dispatch_uid="pretixbase_order_paid_giftcards") diff --git a/src/pretix/plugins/banktransfer/tasks.py b/src/pretix/plugins/banktransfer/tasks.py index 15c084d57..174ff437e 100644 --- a/src/pretix/plugins/banktransfer/tasks.py +++ b/src/pretix/plugins/banktransfer/tasks.py @@ -267,8 +267,9 @@ def _handle_transaction(trans: BankTransaction, matches: tuple, event: Event = N if created: # We're perform a payment method switching on-demand here - old_fee, new_fee, fee, p = change_payment_provider(order, p.payment_provider, p.amount, - new_payment=p, create_log=False) # noqa + old_fee, new_fee, fee, p, new_invoice_created = change_payment_provider( + order, p.payment_provider, p.amount, new_payment=p, create_log=False + ) # noqa if fee: p.fee = fee p.save(update_fields=['fee']) diff --git a/src/pretix/presale/views/order.py b/src/pretix/presale/views/order.py index 68396c0e2..e373e14d9 100644 --- a/src/pretix/presale/views/order.py +++ b/src/pretix/presale/views/order.py @@ -86,7 +86,6 @@ from pretix.base.signals import order_modified, register_ticket_outputs from pretix.base.templatetags.money import money_filter from pretix.base.views.mixins import OrderQuestionsViewMixin from pretix.base.views.tasks import AsyncAction -from pretix.helpers import OF_SELF from pretix.helpers.http import redirect_to_url from pretix.helpers.safedownload import check_token from pretix.multidomain.urlreverse import build_absolute_uri, eventreverse @@ -445,22 +444,8 @@ class OrderPaymentConfirm(EventViewMixin, OrderDetailMixin, TemplateView): def post(self, request, *args, **kwargs): try: - with transaction.atomic(): - order = Order.objects.select_for_update(of=OF_SELF).get(pk=self.order.pk) - i = order.invoices.filter(is_cancellation=False).last() - has_active_invoice = i and not i.canceled - if (not has_active_invoice or order.invoice_dirty) and invoice_qualified(order): - if self.request.event.settings.get('invoice_generate') == 'True' or ( - self.request.event.settings.get('invoice_generate') == 'paid' and self.payment.payment_provider.requires_invoice_immediately): - if has_active_invoice: - generate_cancellation(i) - i = generate_invoice(order) - order.log_action('pretix.event.order.invoice.generated', data={ - 'invoice': i.pk - }) - messages.success(self.request, _('An invoice has been generated.')) - self.payment.process_initiated = True - self.payment.save(update_fields=['process_initiated']) + self.payment.process_initiated = True + self.payment.save(update_fields=['process_initiated']) resp = self.payment.payment_provider.execute_payment(request, self.payment) except PaymentException as e: messages.error(request, str(e)) @@ -674,7 +659,12 @@ class OrderPayChangeMethod(EventViewMixin, OrderDetailMixin, TemplateView): request.session['payment_change_{}'.format(self.order.pk)] = '1' with transaction.atomic(): - old_fee, new_fee, fee, newpayment = change_payment_provider(self.order, p['provider'], None) + old_fee, new_fee, fee, newpayment, new_invoice_created = change_payment_provider( + self.order, p['provider'], None + ) + + if new_invoice_created: + messages.success(self.request, _('An invoice has been generated.')) resp = p['provider'].payment_prepare(request, newpayment) if isinstance(resp, str):