Pluggable invoice transmission methods (#5020)

* Flexible invoice transmission

* UI work

* Add peppol and output

* API support

* Profile integration

* Simplify form for individuals

* Remove sent_to_customer usage

* more steps

* Revert "Bank transfer: Allow to send the invoice direclty to the accounting department (#2975)"

This reverts commit cea6c340be.

* minor fixes

* Fixes after rebase

* update stati

* Backend view

* Transmit and show status

* status, retransmission

* API retransmission

* More fields

* API docs

* Plugin docs

* Update migration

* Add missing license headers

* Remove dead code, fix current tests

* Run isort

* Update regex

* Rebase migration

* Fix migration

* Add tests, fix bugs

* Rebase migration

* Apply suggestion from @luelista

Co-authored-by: luelista <weller@rami.io>

* Apply suggestion from @luelista

Co-authored-by: luelista <weller@rami.io>

* Apply suggestion from @luelista

Co-authored-by: luelista <weller@rami.io>

* Apply suggestion from @luelista

Co-authored-by: luelista <weller@rami.io>

* Apply suggestion from @luelista

Co-authored-by: luelista <weller@rami.io>

* Make migration reversible

* Add TransmissionType.enforce_transmission

* Fix registries API usage after rebase

* Remove code I forgot to delete

* Update transmission status display depending on type

* Add testmode_supported

* Update src/pretix/static/pretixbase/js/addressform.js

Co-authored-by: luelista <weller@rami.io>

* Update src/pretix/static/pretixbase/js/addressform.js

Co-authored-by: luelista <weller@rami.io>

* Update src/pretix/static/pretixbase/js/addressform.js

Co-authored-by: luelista <weller@rami.io>

* New mechanism for non-required invoice forms

* Update src/pretix/base/invoicing/transmission.py

Co-authored-by: luelista <weller@rami.io>

* Declare testmode_supported for email

* Make transmission_email_other an implementation detail

* Fix failing tests and add new ones

* Update src/pretix/base/services/invoices.py

Co-authored-by: luelista <weller@rami.io>

* Add emails to email history

* Fix comma error

* More generic default email text

* Cleanup

* Remove "email invoices" button and refine logic

* Rebase migration

* Fix edge case

---------

Co-authored-by: luelista <weller@rami.io>
This commit is contained in:
Raphael Michel
2025-08-19 17:59:45 +02:00
committed by GitHub
parent 37910f6037
commit 05c74b7ad6
65 changed files with 4514 additions and 1825 deletions

View File

@@ -1130,7 +1130,7 @@ class QuestionsStep(QuestionsViewMixin, CartMixin, TemplateFlowStep):
'invoice' in self.request.GET or
# Checking for self.invoice_address.pk is not enough as when an invoice_address has been added and later edited to be empty, its not None.
# So check initial values as invoice_form can receive pre-filled values from invoice_address, widget-data or overwrites from plug-ins.
is_form_filled(self.invoice_form, ignore_keys=('is_business', 'country'))
is_form_filled(self.invoice_form, ignore_keys=('is_business', 'country', 'transmission_type'))
)
if self.cart_customer:
@@ -1144,6 +1144,7 @@ class QuestionsStep(QuestionsViewMixin, CartMixin, TemplateFlowStep):
"_state_for_address": a.state_for_address,
"_name": a.name,
"is_business": "business" if a.is_business else "individual",
**a.transmission_info,
}
if a.name_parts:
name_parts = a.name_parts
@@ -1165,7 +1166,8 @@ class QuestionsStep(QuestionsViewMixin, CartMixin, TemplateFlowStep):
for k in (
"company", "street", "zipcode", "city", "country", "state",
"state_for_address", "vat_id", "custom_field", "internal_reference", "beneficiary"
"state_for_address", "vat_id", "custom_field", "internal_reference", "beneficiary",
"transmission_type",
):
v = getattr(a, k) or ""
# always add all values of an address even when empty,

View File

@@ -111,6 +111,10 @@
<dt>{% trans "Internal reference" %}</dt>
<dd>{{ addr.internal_reference }}</dd>
{% endif %}
{% for k, v in addr.describe_transmission %}
<dt>{{ k }}</dt>
<dd>{{ v }}</dd>
{% endfor %}
</dl>
</div>
</div>

View File

@@ -40,7 +40,9 @@
{% if addresses_data %}
{{ addresses_data|json_script:"addresses_json" }}
{% endif %}
<div id="invoice" class="profile-scope" data-profiles-id="addresses_json">
<div id="invoice" class="profile-scope"
data-profiles-id="addresses_json"
data-address-information-url="{% url "js_helpers.address_form" %}?invoice=true&organizer={{ event.organizer.slug|urlencode }}&event={{ event.slug|urlencode }}">
<div class="panel-body">
{% if addresses_data %}
<div class="form-group profile-select-container js-do-not-copy-answers">
@@ -78,7 +80,7 @@
</h3>
</summary>
<div>
<div class="panel-body questions-form">
<div class="panel-body questions-form" data-address-information-url="{% url "js_helpers.address_form" %}">
{% if event.settings.attendee_data_explanation_text and pos.item.ask_attendee_data %}
{{ event.settings.attendee_data_explanation_text|rich_text }}
{% endif %}

View File

@@ -335,6 +335,10 @@
<dt>{% trans "Internal Reference" %}</dt>
<dd>{{ order.invoice_address.internal_reference }}</dd>
{% endif %}
{% for k, v in order.invoice_address.describe_transmission %}
<dt>{{ k }}</dt>
<dd>{{ v }}</dd>
{% endfor %}
{% endif %}
</dl>
</div>

View File

@@ -35,14 +35,15 @@
</strong>
</h4>
</summary>
<div id="invoice" class="panel-collapse">
<div id="invoice" class="panel-collapse"
data-address-information-url="{% url "js_helpers.address_form" %}?invoice=true&organizer={{ event.organizer.slug|urlencode }}&event={{ event.slug|urlencode }}">
<div class="panel-body">
{% if event.settings.invoice_address_explanation_text %}
<div>
{{ event.settings.invoice_address_explanation_text|rich_text }}
</div>
{% endif %}
{% bootstrap_form invoice_form layout="horizontal" %}
{% bootstrap_form invoice_form layout="checkout" %}
</div>
</div>
</details>