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

@@ -27,7 +27,8 @@
{% endif %}</strong>
</h4>
</summary>
<div id="invoice">
<div id="invoice"
data-address-information-url="{% url "js_helpers.address_form" %}?invoice=true&organizer={{ request.event.organizer.slug|urlencode }}&event={{ request.event.slug|urlencode }}">
<div class="panel-body">
{% bootstrap_form invoice_form layout="horizontal" %}
</div>

View File

@@ -271,24 +271,70 @@
<a href="{% url "control:event.invoice.download" invoice=i.pk event=request.event.slug organizer=request.event.organizer.slug %}" target="_blank">
{% if i.is_cancellation %}{% trans "Cancellation" context "invoice" %}{% else %}{% trans "Invoice" %}{% endif %}
{{ i.number }}</a>
({{ i.date|date:"SHORT_DATE_FORMAT" }})
{% if i.sent_to_customer.year == 1970 %}
<span class="fa-stack fa-stack-small" data-toggle="tooltip" title="{% trans "We don't know if this invoice was emailed to the customer since it was created before our system tracked this information" %}">
({{ i.date|date:"SHORT_DATE_FORMAT" }}, {{ i.transmission_type_instance.verbose_name }})
{% if i.transmission_status == "unknown" %}
{# Legacy invoice, before the introduction of transmission status #}
{% if i.transmission_date.year == 1970 %}
<span class="fa-stack fa-stack-small" data-toggle="tooltip" title="{% trans "We don't know if this invoice was emailed to the customer since it was created before our system tracked this information" %}">
<span class="fa fa-background fa-envelope text-muted fa-stack-1x"></span>
<span class="fa fa-question fa-stack-1x fa-stack-shifted"></span>
</span>
{% elif i.transmission_date %}
<span class="fa-stack fa-stack-small" data-toggle="tooltip" title="{% trans "Invoice was emailed to customer" %}">
<span class="fa fa-background fa-envelope text-muted fa-stack-1x"></span>
<span class="fa fa-check text-success fa-stack-1x fa-stack-shifted"></span>
</span>
{% else %}
<span class="fa-stack fa-stack-small" data-toggle="tooltip" title="{% trans "Invoice was not yet emailed to customer" %}">
<span class="fa fa-background fa-envelope text-muted fa-stack-1x"></span>
</span>
{% endif %}
{% elif i.transmission_status == "pending" %}
{% if i.transmission_type_instance.enforce_transmission %}
<span class="fa-stack fa-stack-small" data-toggle="tooltip" title="{% trans "Invoice is scheduled to be transmitted" %}">
<span class="fa fa-background fa-envelope text-muted fa-stack-1x"></span>
<span class="fa fa-clock-o text-success fa-stack-1x fa-stack-shifted"></span>
</span>
{% else %}
<span class="fa fa-envelope fa-background text-muted" data-toggle="tooltip" title="{% trans "Invoice is not yet transmitted" %}"></span>
{% endif %}
{% elif i.transmission_status == "inflight" %}
<span class="fa-stack fa-stack-small" data-toggle="tooltip" title="{% trans "Invoice is currently in transmission" %}">
<span class="fa fa-background fa-envelope text-muted fa-stack-1x"></span>
<span class="fa fa-question fa-stack-1x fa-stack-shifted"></span>
<span class="fa fa-send text-success fa-stack-1x fa-stack-shifted"></span>
</span>
{% elif i.sent_to_customer %}
<span class="fa-stack fa-stack-small" data-toggle="tooltip" title="{% trans "Invoice was emailed to customer" %}">
{% elif i.transmission_status == "testmode_ignored" %}
<span class="fa-stack fa-stack-small" data-toggle="tooltip" title="{% trans "Invoice not transmitted in test mode" %}">
<span class="fa fa-background fa-envelope text-muted fa-stack-1x"></span>
<span class="fa fa-ban text-warning fa-stack-1x fa-stack-shifted"></span>
</span>
{% elif i.transmission_status == "failed" %}
<span class="fa-stack fa-stack-small" data-toggle="tooltip" title="{% trans "Invoice transmission failed" %}">
<span class="fa fa-background fa-envelope text-muted fa-stack-1x"></span>
<span class="fa fa-exclamation-circle text-danger fa-stack-1x fa-stack-shifted"></span>
</span>
{% elif i.transmission_status == "completed" %}
<span class="fa-stack fa-stack-small" data-toggle="tooltip" title="{% trans "Invoice has been transmitted" %}">
<span class="fa fa-background fa-envelope text-muted fa-stack-1x"></span>
<span class="fa fa-check text-success fa-stack-1x fa-stack-shifted"></span>
</span>
{% else %}
<span class="fa-stack fa-stack-small" data-toggle="tooltip" title="{% trans "Invoice was not yet emailed to customer" %}">
<span class="fa fa-background fa-envelope text-muted fa-stack-1x"></span>
</span>
{% endif %}
{% if i.transmission_status != "inflight" %}
<form class="form-inline helper-display-inline" method="post"
action="{% url "control:event.order.retransmitinvoice" event=request.event.slug organizer=request.event.organizer.slug code=order.code id=i.pk %}">
{% csrf_token %}
<button class="btn btn-default btn-xs" data-toggle="tooltip"
title="{{ i.transmission_type_instance.verbose_name }}">
{% if i.transmission_status == "pending" %}
{% trans "Transmit" %}
{% else %}
{% trans "Retransmit" %}
{% endif %}
</button>
</form>
{% endif %}
{% if not i.canceled %}
{% if request.event.settings.invoice_regenerate_allowed %}
{% if i.regenerate_allowed %}
<form class="form-inline helper-display-inline" method="post"
action="{% url "control:event.order.regeninvoice" event=request.event.slug organizer=request.event.organizer.slug code=order.code id=i.pk %}">
{% csrf_token %}
@@ -320,12 +366,6 @@
<br/>
{% endif %}
{% endfor %}
{% if invoices_send_link %}
<br/>
<a class="btn btn-default btn-xs" href="{{ invoices_send_link }}">
{% trans "Email invoices" %}
</a>
{% endif %}
{% if can_generate_invoice and 'can_change_orders' in request.eventpermset %}
<br/>
<form class="form-inline helper-display-inline" method="post"
@@ -989,8 +1029,14 @@
<dt>{{ request.event.settings.invoice_address_custom_field }}</dt>
<dd>{{ order.invoice_address.custom_field }}</dd>
{% endif %}
<dt>{% trans "Internal reference" %}</dt>
<dd>{{ order.invoice_address.internal_reference }}</dd>
{% if order.invoice_address.internal_reference %}
<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 %}
</dl>
</div>
</div>