From 51f52ffe406b9de7b1a98b345aa699b5332e4931 Mon Sep 17 00:00:00 2001 From: Kara Engelhardt Date: Mon, 10 Aug 2026 16:53:43 +0200 Subject: [PATCH] Transmit invoices generated due to paymentprovider changes (Z#23242806) --- src/pretix/base/services/orders.py | 19 +++++++++------ src/tests/presale/test_orders.py | 37 ++++++++++++++++++++++++++++-- 2 files changed, 47 insertions(+), 9 deletions(-) diff --git a/src/pretix/base/services/orders.py b/src/pretix/base/services/orders.py index 23b21c9be1..3b5d05087e 100644 --- a/src/pretix/base/services/orders.py +++ b/src/pretix/base/services/orders.py @@ -3438,7 +3438,7 @@ def change_payment_provider(order: Order, payment_provider, amount=None, new_pay } ) - new_invoice_created = False + new_invoice = None if recreate_invoices: # Lock to prevent duplicate invoice creation order = Order.objects.select_for_update(of=OF_SELF).get(pk=order.pk) @@ -3449,13 +3449,16 @@ def change_payment_provider(order: Order, payment_provider, amount=None, new_pay if has_active_invoice and order.total != oldtotal: try: generate_cancellation(i) - generate_invoice(order) + new_invoice = generate_invoice(order) except Exception as e: logger.exception("Could not generate invoice.") order.log_action("pretix.event.order.invoice.failed", data={ "exception": str(e) }) - new_invoice_created = True + else: + order.log_action('pretix.event.order.invoice.generated', data={ + 'invoice': new_invoice.pk + }) elif (not has_active_invoice or order.invoice_dirty) and invoice_qualified(order): if order.event.settings.get('invoice_generate') == 'True' or ( @@ -3465,10 +3468,9 @@ def change_payment_provider(order: Order, payment_provider, amount=None, new_pay try: if has_active_invoice: generate_cancellation(i) - i = generate_invoice(order) - new_invoice_created = True + new_invoice = generate_invoice(order) order.log_action('pretix.event.order.invoice.generated', data={ - 'invoice': i.pk + 'invoice': new_invoice.pk }) except Exception as e: logger.exception("Could not generate invoice.") @@ -3476,8 +3478,11 @@ def change_payment_provider(order: Order, payment_provider, amount=None, new_pay "exception": str(e) }) + if new_invoice and invoice_transmission_separately(new_invoice): + transmit_invoice.apply_async(args=(order.event_id, new_invoice.pk, False)) + order.create_transactions() - return old_fee, new_fee, fee, new_payment, new_invoice_created + return old_fee, new_fee, fee, new_payment, bool(new_invoice) @receiver(order_paid, dispatch_uid="pretixbase_order_paid_giftcards") diff --git a/src/tests/presale/test_orders.py b/src/tests/presale/test_orders.py index 9606938b80..c55836dc31 100644 --- a/src/tests/presale/test_orders.py +++ b/src/tests/presale/test_orders.py @@ -37,18 +37,20 @@ import re from decimal import Decimal from bs4 import BeautifulSoup +from django.core import mail as djmail from django.core.files.uploadedfile import SimpleUploadedFile from django.test import TestCase from django.utils.timezone import now from django_scopes import scopes_disabled from pretix.base.models import ( - Event, Item, ItemCategory, ItemVariation, Order, OrderPosition, Organizer, - Question, Quota, + Event, Invoice, InvoiceAddress, Item, ItemCategory, ItemVariation, Order, + OrderPosition, Organizer, Question, Quota, ) from pretix.base.models.orders import OrderFee, OrderPayment from pretix.base.reldate import RelativeDate, RelativeDateWrapper from pretix.base.services.invoices import generate_invoice +from pretix.testutils.scope import classscope class BaseOrdersTest(TestCase): @@ -1702,6 +1704,37 @@ class OrdersTest(BaseOrdersTest): assert 'Gift card' in response.content.decode() assert '1 available' in response.content.decode() + @classscope("orga") + def test_change_paymentmethod_invoice_separately(self): + self.event.settings.payment_banktransfer__enabled = True + self.event.settings.payment_banktransfer_invoice_immediately = True + self.event.settings.invoice_generate = "paid" + InvoiceAddress.objects.create( + order=self.order, + transmission_type="email", + transmission_info={ + "transmission_email_other": True, + "transmission_email_address": "invoice@example.org", + } + ) + + assert self.order.invoices.count() == 0 + + with self.captureOnCommitCallbacks(execute=True): + self.client.post( + '/%s/%s/order/%s/%s/pay/change' % (self.orga.slug, self.event.slug, self.order.code, self.order.secret), + { + 'payment': 'banktransfer' + } + ) + + assert self.order.payments.last().provider == 'banktransfer' + assert self.order.invoices.count() == 1 + i = self.order.invoices.last() + assert i.transmission_status == Invoice.TRANSMISSION_STATUS_COMPLETED + assert ["invoice@example.org"] == djmail.outbox[0].to + assert any(["Invoice_" in a[0] for a in djmail.outbox[0].attachments]) + def test_answer_download_token(self): with scopes_disabled(): q = self.event.questions.create(question="Foo", type="F")