mirror of
https://github.com/pretix/pretix.git
synced 2026-05-06 15:24:02 +00:00
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:
@@ -1,83 +1,127 @@
|
||||
$(function () {
|
||||
"use strict";
|
||||
|
||||
$("select[data-country-information-url]").each(function () {
|
||||
$("[data-address-information-url]").each(function () {
|
||||
let xhr;
|
||||
const dependency = $(this),
|
||||
loader = $("<span class='fa fa-cog fa-spin'></span>").hide().prependTo(dependency.closest(".form-group").find("label")),
|
||||
url = this.getAttribute('data-country-information-url'),
|
||||
form = dependency.closest(".panel-body, form, .profile-scope"),
|
||||
isRequired = dependency.closest(".form-group").is(".required"),
|
||||
dependents = {
|
||||
'city': form.find("input[name$=city]"),
|
||||
'zipcode': form.find("input[name$=zipcode]"),
|
||||
'street': form.find("textarea[name$=street]"),
|
||||
'state': form.find("select[name$=state]"),
|
||||
'vat_id': form.find("input[name$=vat_id]"),
|
||||
},
|
||||
update = function (ev) {
|
||||
if (xhr) {
|
||||
xhr.abort();
|
||||
const form = $(this);
|
||||
const dependencies = $(this).find("[data-trigger-address-info]");
|
||||
const loader = $("<span class='fa fa-cog fa-spin'></span>").hide().prependTo(dependencies.closest(".form-group").find("label").first())
|
||||
const baseUrl = this.getAttribute('data-address-information-url')
|
||||
const isAnyRequired = dependencies.toArray().some(function (e) { return $(e).closest(".form-group").is(".required") });
|
||||
|
||||
const dependents = {
|
||||
'city': form.find("input[name$=city]"),
|
||||
'zipcode': form.find("input[name$=zipcode]"),
|
||||
'street': form.find("textarea[name$=street]"),
|
||||
'state': form.find("select[name$=state]"),
|
||||
'vat_id': form.find("input[name$=vat_id]"),
|
||||
};
|
||||
|
||||
form.find("select[name*=transmission_], textarea[name*=transmission_], input[name*=transmission_]").each(function () {
|
||||
dependents[$(this).attr("name").split("-").pop()] = $(this)
|
||||
})
|
||||
|
||||
const update = function (ev) {
|
||||
if (xhr) {
|
||||
xhr.abort();
|
||||
}
|
||||
|
||||
dependents.state.prop("data-selected-value", dependents.state.val());
|
||||
if (dependents.transmission_type) {
|
||||
dependents.transmission_type.prop("data-selected-value", dependents.transmission_type.val());
|
||||
}
|
||||
|
||||
for (var k in dependents) dependents[k].prop("disabled", true);
|
||||
loader.show();
|
||||
var url = new URL(baseUrl, location.href);
|
||||
// Address depends on all annotated fields
|
||||
form.find("[data-trigger-address-info]").each(function () {
|
||||
// Remove prefix of the form to get actual field name
|
||||
if (($(this).attr("type") === "radio" || $(this).attr("type") === "checkbox") && !$(this).prop("checked")) {
|
||||
return
|
||||
}
|
||||
for (var k in dependents) dependents[k].prop("disabled", true);
|
||||
loader.show();
|
||||
xhr = $.getJSON(url + '?country=' + dependency.val(), function (data) {
|
||||
var selected_value = dependents.state.prop("data-selected-value");
|
||||
if (selected_value) dependents.state.prop("data-selected-value", "");
|
||||
dependents.state.find("option:not([value=''])").remove();
|
||||
if (data.data.length > 0) {
|
||||
$.each(data.data, function (k, s) {
|
||||
var o = $("<option>").attr("value", s.code).text(s.name);
|
||||
if (selected_value == s.code) o.prop("selected", true);
|
||||
dependents.state.append(o);
|
||||
});
|
||||
}
|
||||
for(var k in dependents) {
|
||||
const options = data[k],
|
||||
dependent = dependents[k];
|
||||
let visible = 'visible' in options ? options.visible : true;
|
||||
|
||||
if (dependent.is("[data-display-dependency]")) {
|
||||
const dependency = $(dependent.attr("data-display-dependency"));
|
||||
visible = visible && (
|
||||
(dependency.attr("type") === 'checkbox' || dependency.attr("type") === 'radio') ? dependency.prop('checked') : !!dependency.val()
|
||||
);
|
||||
}
|
||||
|
||||
if ('label' in options) {
|
||||
dependent.closest(".form-group").find(".control-label").text(options.label);
|
||||
}
|
||||
|
||||
const required = 'required' in options && options.required && isRequired && visible;
|
||||
dependent.closest(".form-group").toggle(visible).toggleClass('required', required);
|
||||
dependent.prop("required", required);
|
||||
const label = dependent.closest(".form-group").find("label");
|
||||
const labelRequired = label.find(".label-required");
|
||||
if (!required) {
|
||||
labelRequired.remove();
|
||||
} else if (!labelRequired.length) {
|
||||
label.append('<i class="label-required">' + gettext('required') + '</i>')
|
||||
}
|
||||
}
|
||||
for (var k in dependents) dependents[k].prop("disabled", false);
|
||||
}).always(function() {
|
||||
loader.hide();
|
||||
}).fail(function(){
|
||||
// In case of errors, show everything and require nothing, we can still handle errors in backend
|
||||
for(var k in dependents) {
|
||||
const dependent = dependents[k],
|
||||
visible = true,
|
||||
required = false;
|
||||
|
||||
dependent.closest(".form-group").toggle(visible).toggleClass('required', required);
|
||||
dependent.prop("required", required);
|
||||
dependent.closest(".form-group").find("label .label-required").remove();
|
||||
}
|
||||
url.searchParams.append($(this).attr("name").split("-").pop(), $(this).val());
|
||||
})
|
||||
if (dependents.transmission_type) {
|
||||
url.searchParams.append("transmission_type_required", !dependents.transmission_type.find("option[value='-']").length);
|
||||
}
|
||||
xhr = $.getJSON(url, function (data) {
|
||||
var selected_state = dependents.state.prop("data-selected-value");
|
||||
if (selected_state) dependents.state.prop("data-selected-value", "");
|
||||
dependents.state.find("option:not([value=''])").remove();
|
||||
$.each(data.data, function (k, s) {
|
||||
var o = $("<option>").attr("value", s.code).text(s.name);
|
||||
if (selected_state === s.code) o.prop("selected", true);
|
||||
dependents.state.append(o);
|
||||
});
|
||||
};
|
||||
dependents.state.prop("data-selected-value", dependents.state.val());
|
||||
|
||||
if (dependents.transmission_type) {
|
||||
var selected_transmission_type = dependents.transmission_type.prop("data-selected-value");
|
||||
if (selected_transmission_type) dependents.transmission_type.prop("data-selected-value", "");
|
||||
dependents.transmission_type.find("option:not([value='']):not([value='-'])").remove();
|
||||
|
||||
if (!data.transmission_type.visible) {
|
||||
selected_transmission_type = "email";
|
||||
}
|
||||
|
||||
$.each(data.transmission_types, function (k, s) {
|
||||
var o = $("<option>").attr("value", s.code).text(s.name);
|
||||
if (selected_transmission_type === s.code) {
|
||||
o.prop("selected", true);
|
||||
}
|
||||
dependents.transmission_type.append(o);
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
for (var k in dependents) {
|
||||
const options = data[k],
|
||||
dependent = dependents[k];
|
||||
let visible = 'visible' in options ? options.visible : true;
|
||||
|
||||
if (dependent.is("[data-display-dependency]")) {
|
||||
const dependency = $(dependent.attr("data-display-dependency"));
|
||||
visible = visible && (
|
||||
(dependency.attr("type") === 'checkbox' || dependency.attr("type") === 'radio') ? dependency.prop('checked') : !!dependency.val()
|
||||
);
|
||||
}
|
||||
|
||||
if ('label' in options) {
|
||||
dependent.closest(".form-group").find(".control-label").text(options.label);
|
||||
}
|
||||
|
||||
const required = 'required' in options && visible && (
|
||||
(options.required === 'if_any' && isAnyRequired) ||
|
||||
(options.required === true)
|
||||
);
|
||||
dependent.closest(".form-group").toggle(visible).toggleClass('required', required);
|
||||
dependent.prop("required", required);
|
||||
|
||||
const label = dependent.closest(".form-group").find("label");
|
||||
const labelRequired = label.find(".label-required");
|
||||
if (!required) {
|
||||
labelRequired.remove();
|
||||
} else if (!labelRequired.length) {
|
||||
label.append('<i class="label-required">' + gettext('required') + '</i>')
|
||||
}
|
||||
}
|
||||
for (var k in dependents) dependents[k].prop("disabled", false);
|
||||
}).always(function() {
|
||||
loader.hide();
|
||||
}).fail(function(){
|
||||
// In case of errors, show everything and require nothing, we can still handle errors in backend
|
||||
for(var k in dependents) {
|
||||
const dependent = dependents[k],
|
||||
visible = true,
|
||||
required = false;
|
||||
|
||||
dependent.closest(".form-group").toggle(visible).toggleClass('required', required);
|
||||
dependent.prop("required", required);
|
||||
}
|
||||
});
|
||||
};
|
||||
update();
|
||||
dependency.on("change", update);
|
||||
dependencies.on("change", update);
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user