Always regenerate dirty invoices in backend OrderChange view if reissue_invoice is set (Z#23230731)

This commit is contained in:
Kara Engelhardt
2026-04-20 14:00:09 +02:00
parent 4530d864d3
commit b3ba6f17f0
3 changed files with 52 additions and 17 deletions

View File

@@ -1651,7 +1651,7 @@ class OrderChangeManager:
raise RuntimeError("Order position has not been created yet. Call commit() first on OrderChangeManager.") raise RuntimeError("Order position has not been created yet. Call commit() first on OrderChangeManager.")
return self._positions return self._positions
def __init__(self, order: Order, user=None, auth=None, notify=True, reissue_invoice=True, allow_blocked_seats=False): def __init__(self, order: Order, user=None, auth=None, notify=True, reissue_invoice=True, allow_blocked_seats=False, force_reissue_invoice=False):
self.order = order self.order = order
self.user = user self.user = user
self.auth = auth self.auth = auth
@@ -1659,6 +1659,7 @@ class OrderChangeManager:
self.split_order = None self.split_order = None
self.reissue_invoice = reissue_invoice self.reissue_invoice = reissue_invoice
self.allow_blocked_seats = allow_blocked_seats self.allow_blocked_seats = allow_blocked_seats
self.force_reissue_invoice = force_reissue_invoice
self._committed = False self._committed = False
self._totaldiff_guesstimate = 0 self._totaldiff_guesstimate = 0
self._quotadiff = Counter() self._quotadiff = Counter()
@@ -2902,25 +2903,29 @@ class OrderChangeManager:
} }
) )
def invoice_should_be_generated_now(self):
i = self.order.invoices.filter(is_cancellation=False).last()
return (
self.event.settings.invoice_generate == "True" or (
self.event.settings.invoice_generate == "paid" and
self.open_payment is not None and
self.open_payment.payment_provider.requires_invoice_immediately
) or (
self.event.settings.invoice_generate == "paid" and
self.order.status == Order.STATUS_PAID
) or (
# Backwards-compatible behaviour
(self.event.settings.invoice_generate not in ("True", "paid") or self.force_reissue_invoice) and
i and
not i.canceled
)
)
def _reissue_invoice(self): def _reissue_invoice(self):
i = self.order.invoices.filter(is_cancellation=False).last() i = self.order.invoices.filter(is_cancellation=False).last()
if self.reissue_invoice and self._invoice_dirty: if self.reissue_invoice and self._invoice_dirty:
order_now_qualified = invoice_qualified(self.order) order_now_qualified = invoice_qualified(self.order)
invoice_should_be_generated_now = ( invoice_should_be_generated_now = self.invoice_should_be_generated_now()
self.event.settings.invoice_generate == "True" or (
self.event.settings.invoice_generate == "paid" and
self.open_payment is not None and
self.open_payment.payment_provider.requires_invoice_immediately
) or (
self.event.settings.invoice_generate == "paid" and
self.order.status == Order.STATUS_PAID
) or (
# Backwards-compatible behaviour
self.event.settings.invoice_generate not in ("True", "paid") and
i and
not i.canceled
)
)
invoice_should_be_generated_later = not invoice_should_be_generated_now and ( invoice_should_be_generated_later = not invoice_should_be_generated_now and (
self.event.settings.invoice_generate in ("True", "paid") self.event.settings.invoice_generate in ("True", "paid")
) )

View File

@@ -1949,8 +1949,11 @@ class OrderChange(OrderView):
@cached_property @cached_property
def other_form(self): def other_form(self):
return OtherOperationsForm(prefix='other', order=self.order, form = OtherOperationsForm(prefix='other', order=self.order,
data=self.request.POST if self.request.method == "POST" else None) data=self.request.POST if self.request.method == "POST" else None)
ocm = OrderChangeManager(self.order)
form.fields['reissue_invoice'].initial = ocm.invoice_should_be_generated_now()
return form
@cached_property @cached_property
def add_position_formset(self): def add_position_formset(self):
@@ -2177,6 +2180,8 @@ class OrderChange(OrderView):
notify=notify, notify=notify,
reissue_invoice=self.other_form.cleaned_data['reissue_invoice'] if self.other_form.is_valid() else True, reissue_invoice=self.other_form.cleaned_data['reissue_invoice'] if self.other_form.is_valid() else True,
allow_blocked_seats=True, allow_blocked_seats=True,
force_reissue_invoice=self.other_form.cleaned_data['reissue_invoice'] if self.other_form.is_valid() else False,
) )
form_valid = (self._process_add_fees(ocm) and form_valid = (self._process_add_fees(ocm) and
self._process_add_positions(ocm) and self._process_add_positions(ocm) and

View File

@@ -2531,6 +2531,31 @@ class OrderChangeManagerTests(BaseOrderChangeManagerTestCase, TestCase):
).confirm() ).confirm()
assert self.order.invoices.count() == 3 assert self.order.invoices.count() == 3
@classscope(attr='o')
def test_force_reissue_invoice_paid(self):
self.event.settings.invoice_generate = "paid"
generate_invoice(self.order)
assert self.order.invoices.count() == 1
self.ocm.force_reissue_invoice = True
self.ocm.add_position(self.ticket, None, Decimal('2.00'))
self.ocm.commit()
assert self.order.invoices.count() == 3
@classscope(attr='o')
def test_force_reissue_invoice_paid_only_after_payment_only_if_enabled(self):
self.event.settings.invoice_generate = "False"
assert self.order.invoices.count() == 0
self.ocm.force_reissue_invoice = True
self.ocm.add_position(self.ticket, None, Decimal('2.00'))
self.ocm.commit()
assert self.order.invoices.count() == 0
self.order.refresh_from_db()
assert not self.order.invoice_dirty
self.order.payments.create(
provider='manual', amount=self.order.total
).confirm()
assert self.order.invoices.count() == 0
@classscope(attr='o') @classscope(attr='o')
def test_reissue_invoice_paid_only_after_payment_only_if_enabled(self): def test_reissue_invoice_paid_only_after_payment_only_if_enabled(self):
self.event.settings.invoice_generate = "False" self.event.settings.invoice_generate = "False"