mirror of
https://github.com/pretix/pretix.git
synced 2025-12-14 13:32:28 +00:00
Compare commits
1 Commits
api-create
...
copy-from-
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
fa372b3df0 |
@@ -1,3 +1,4 @@
|
|||||||
|
import itertools
|
||||||
import json
|
import json
|
||||||
from collections import OrderedDict
|
from collections import OrderedDict
|
||||||
from decimal import Decimal
|
from decimal import Decimal
|
||||||
@@ -53,7 +54,31 @@ class BaseQuestionsViewMixin:
|
|||||||
data=(self.request.POST if self.request.method == 'POST' else None),
|
data=(self.request.POST if self.request.method == 'POST' else None),
|
||||||
files=(self.request.FILES if self.request.method == 'POST' else None))
|
files=(self.request.FILES if self.request.method == 'POST' else None))
|
||||||
form.pos = cartpos or orderpos
|
form.pos = cartpos or orderpos
|
||||||
form.show_copy_answers_to_addon_button = form.pos.addon_to and set(form.pos.addon_to.item.questions.all()) & set(form.pos.item.questions.all())
|
|
||||||
|
if form.pos.addon_to_id is not None:
|
||||||
|
form.copy_answer_from = None
|
||||||
|
# addons typically do not have the same item as the main position, so we look for overlapping questions
|
||||||
|
form.show_copy_answers_to_addon_button = bool(
|
||||||
|
set(form.pos.addon_to.item.questions.values_list("id", flat=True)) &
|
||||||
|
set(form.pos.item.questions.values_list("id", flat=True)))
|
||||||
|
else:
|
||||||
|
form.show_copy_answers_to_addon_button = False
|
||||||
|
# look for a position we can best copy answers from
|
||||||
|
form.copy_answer_from = next(
|
||||||
|
itertools.chain(
|
||||||
|
( # match a position with the same item
|
||||||
|
other_form.pos.id for other_form in formlist
|
||||||
|
if other_form.pos.addon_to_id is None and form.pos.item.id == other_form.pos.item.id
|
||||||
|
),
|
||||||
|
( # match a position with questions in common
|
||||||
|
other_form.pos.id for other_form in formlist
|
||||||
|
if other_form.pos.addon_to_id is None
|
||||||
|
and set(form.pos.item.questions.values_list("id", flat=True)) & set(other_form.pos.item.questions.values_list("id", flat=True))
|
||||||
|
)
|
||||||
|
),
|
||||||
|
None # didn't find a position to copy answers from
|
||||||
|
)
|
||||||
|
|
||||||
if len(form.fields) > 0:
|
if len(form.fields) > 0:
|
||||||
formlist.append(form)
|
formlist.append(form)
|
||||||
return formlist
|
return formlist
|
||||||
@@ -105,8 +130,7 @@ class BaseQuestionsViewMixin:
|
|||||||
if hasattr(field, 'answer'):
|
if hasattr(field, 'answer'):
|
||||||
# We already have a cached answer object, so we don't
|
# We already have a cached answer object, so we don't
|
||||||
# have to create a new one
|
# have to create a new one
|
||||||
if v == '' or v is None or (isinstance(field, forms.FileField) and v is False) \
|
if v == '' or v is None or (isinstance(field, forms.FileField) and v is False) or (isinstance(v, QuerySet) and not v.exists()):
|
||||||
or (isinstance(v, QuerySet) and not v.exists()):
|
|
||||||
if field.answer.file:
|
if field.answer.file:
|
||||||
field.answer.file.delete()
|
field.answer.file.delete()
|
||||||
field.answer.delete()
|
field.answer.delete()
|
||||||
|
|||||||
@@ -60,9 +60,9 @@
|
|||||||
{% if pos.variation %}
|
{% if pos.variation %}
|
||||||
– {{ pos.variation }}
|
– {{ pos.variation }}
|
||||||
{% endif %}
|
{% endif %}
|
||||||
{% if forloop.counter > 1 %}
|
{% if forms.0.copy_answer_from is not None %}
|
||||||
<span class="text-right flip">
|
<span class="text-right flip">
|
||||||
<button type="button" data-id="{{ forloop.counter0 }}" name="copy" class="js-copy-answers btn btn-default btn-xs">{% trans "Copy answers from above" %}</button>
|
<button type="button" data-id="{{ forms.0.pos.id }}" data-copy-from="{{ forms.0.copy_answer_from }}" name="copy" class="js-copy-answers btn btn-default btn-xs">{% trans "Copy answers from above" %}</button>
|
||||||
<i class="fa fa-angle-down collapse-indicator"></i>
|
<i class="fa fa-angle-down collapse-indicator"></i>
|
||||||
</span>
|
</span>
|
||||||
{% else %}
|
{% else %}
|
||||||
@@ -122,13 +122,13 @@
|
|||||||
<legend>
|
<legend>
|
||||||
{% if form.show_copy_answers_to_addon_button %}
|
{% if form.show_copy_answers_to_addon_button %}
|
||||||
<span class="pull-right flip">
|
<span class="pull-right flip">
|
||||||
<button type="button" data-id="{{ forloop.parentloop.counter0 }}" data-addonid="{{ forloop.counter0 }}" name="copy" class="js-copy-answers-addon btn btn-default btn-xs">{% trans "Copy answers" %}</button>
|
<button type="button" data-id="{{ forms.0.pos.id }}" data-addonid="{{ forloop.counter0 }}" name="copy" class="js-copy-answers-addon btn btn-default btn-xs">{% trans "Copy answers" %}</button>
|
||||||
</span>
|
</span>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
+ {{ form.pos.item.name }}{% if form.pos.variation %} – {{ form.pos.variation.value }}{% endif %}
|
+ {{ form.pos.item.name }}{% if form.pos.variation %} – {{ form.pos.variation.value }}{% endif %}
|
||||||
</legend>
|
</legend>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
<div data-idx="{{ forloop.parentloop.counter0 }}" data-addonidx="{{ forloop.counter0 }}">
|
<div data-idx="{{ forms.0.pos.id }}" data-addonidx="{{ forloop.counter0 }}">
|
||||||
{% bootstrap_form form layout="checkout" %}
|
{% bootstrap_form form layout="checkout" %}
|
||||||
</div>
|
</div>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
|
|||||||
@@ -16,9 +16,13 @@ function ngettext(singular, plural, count) {
|
|||||||
|
|
||||||
function interpolate(fmt, object, named) {
|
function interpolate(fmt, object, named) {
|
||||||
if (named) {
|
if (named) {
|
||||||
return fmt.replace(/%\(\w+\)s/g, function(match){return String(obj[match.slice(2,-2)])});
|
return fmt.replace(/%\(\w+\)s/g, function (match) {
|
||||||
|
return String(obj[match.slice(2, -2)])
|
||||||
|
});
|
||||||
} else {
|
} else {
|
||||||
return fmt.replace(/%s/g, function(match){return String(obj.shift())});
|
return fmt.replace(/%s/g, function (match) {
|
||||||
|
return String(obj.shift())
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -171,13 +175,13 @@ $(function () {
|
|||||||
$(".js-copy-answers").click(function (e) {
|
$(".js-copy-answers").click(function (e) {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
e.stopPropagation();
|
e.stopPropagation();
|
||||||
let idx = $(this).data('id');
|
const idx = $(this).data('id');
|
||||||
const addonDivs = $('div[data-idx="' + idx +'"]')
|
const copyFromIdx = $(this).data('copy-from')
|
||||||
|
const addonDivs = $('div[data-idx="' + idx + '"]')
|
||||||
addonDivs.each(function (index) {
|
addonDivs.each(function (index) {
|
||||||
const elements = $(this).find('input, select, textarea');
|
const elements = $(this).find('input, select, textarea');
|
||||||
|
const addonIdx = $(this).data("addonidx");
|
||||||
const addonIdx = $(this).attr("data-addonidx");
|
const answersDiv = $('div[data-idx="' + copyFromIdx + '"][data-addonidx="' + addonIdx + '"]');
|
||||||
const answersDiv = $('div[data-idx="0"][data-addonidx="' + addonIdx + '"]');
|
|
||||||
const answers = answersDiv.find('input, select, textarea');
|
const answers = answersDiv.find('input, select, textarea');
|
||||||
|
|
||||||
copy_answers(elements, answers);
|
copy_answers(elements, answers);
|
||||||
@@ -189,7 +193,7 @@ $(function () {
|
|||||||
e.stopPropagation();
|
e.stopPropagation();
|
||||||
const id = $(this).data('id');
|
const id = $(this).data('id');
|
||||||
const addonId = $(this).data('addonid');
|
const addonId = $(this).data('addonid');
|
||||||
const addonDiv = $('div[data-idx="' + id +'"][data-addonidx="' + addonId + '"]');
|
const addonDiv = $('div[data-idx="' + id + '"][data-addonidx="' + addonId + '"]');
|
||||||
const elements = addonDiv.find('input, select, textarea');
|
const elements = addonDiv.find('input, select, textarea');
|
||||||
const answers = $('*[data-idx="' + id + '"] input, *[data-idx="' + id + '"] select, *[data-idx="' + id + '"] textarea');
|
const answers = $('*[data-idx="' + id + '"] input, *[data-idx="' + id + '"] select, *[data-idx="' + id + '"] textarea');
|
||||||
copy_answers(elements, answers);
|
copy_answers(elements, answers);
|
||||||
@@ -249,7 +253,7 @@ $(function () {
|
|||||||
is_enabled = true;
|
is_enabled = true;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
$(".input-seat-selection option").each(function() {
|
$(".input-seat-selection option").each(function () {
|
||||||
if ($(this).val() && $(this).val() !== "" && $(this).prop('selected')) {
|
if ($(this).val() && $(this).val() !== "" && $(this).prop('selected')) {
|
||||||
is_enabled = true;
|
is_enabled = true;
|
||||||
}
|
}
|
||||||
@@ -257,7 +261,9 @@ $(function () {
|
|||||||
}
|
}
|
||||||
if (!is_enabled && !$(".has-seating").length) {
|
if (!is_enabled && !$(".has-seating").length) {
|
||||||
$("#btn-add-to-cart").prop("disabled", !is_enabled).popover({
|
$("#btn-add-to-cart").prop("disabled", !is_enabled).popover({
|
||||||
'content': function () { return gettext("Please enter a quantity for one of the ticket types.") },
|
'content': function () {
|
||||||
|
return gettext("Please enter a quantity for one of the ticket types.")
|
||||||
|
},
|
||||||
'placement': 'top',
|
'placement': 'top',
|
||||||
'trigger': 'hover focus'
|
'trigger': 'hover focus'
|
||||||
});
|
});
|
||||||
@@ -353,7 +359,9 @@ $(function () {
|
|||||||
if (counter > curCounter) {
|
if (counter > curCounter) {
|
||||||
return; // Lost race
|
return; // Lost race
|
||||||
}
|
}
|
||||||
dependent.find("option").filter(function (t) {return !!$(this).attr("value")}).remove();
|
dependent.find("option").filter(function (t) {
|
||||||
|
return !!$(this).attr("value")
|
||||||
|
}).remove();
|
||||||
if (data.data.length > 0) {
|
if (data.data.length > 0) {
|
||||||
$.each(data.data, function (k, s) {
|
$.each(data.data, function (k, s) {
|
||||||
dependent.append($("<option>").attr("value", s.code).text(s.name));
|
dependent.append($("<option>").attr("value", s.code).text(s.name));
|
||||||
@@ -400,8 +408,7 @@ $(function () {
|
|||||||
true
|
true
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
var cancel_fee_slider = $('#cancel-fee-slider').slider({
|
var cancel_fee_slider = $('#cancel-fee-slider').slider({}).on('slide', function () {
|
||||||
}).on('slide', function () {
|
|
||||||
cancel_fee_slider_update();
|
cancel_fee_slider_update();
|
||||||
}).data('slider');
|
}).data('slider');
|
||||||
if (cancel_fee_slider) {
|
if (cancel_fee_slider) {
|
||||||
@@ -417,7 +424,7 @@ $(function () {
|
|||||||
}
|
}
|
||||||
|
|
||||||
var local_tz = moment.tz.guess()
|
var local_tz = moment.tz.guess()
|
||||||
$("span[data-timezone]").each(function() {
|
$("span[data-timezone]").each(function () {
|
||||||
var t = moment.tz($(this).attr("data-time"), $(this).attr("data-timezone"))
|
var t = moment.tz($(this).attr("data-time"), $(this).attr("data-timezone"))
|
||||||
var tz = moment.tz.zone($(this).attr("data-timezone"))
|
var tz = moment.tz.zone($(this).attr("data-timezone"))
|
||||||
|
|
||||||
@@ -445,39 +452,47 @@ $(function () {
|
|||||||
});
|
});
|
||||||
|
|
||||||
function copy_answers(elements, answers) {
|
function copy_answers(elements, answers) {
|
||||||
elements.each(function (index) {
|
elements.each(function (index) {
|
||||||
var input = $(this),
|
var input = $(this),
|
||||||
tagName = input.prop('tagName').toLowerCase(),
|
tagName = input.prop('tagName').toLowerCase(),
|
||||||
attributeType = input.attr('type'),
|
attributeType = input.attr('type'),
|
||||||
suffix = input.attr('name').split('-')[1];
|
suffix = input.attr('name').split('-')[1];
|
||||||
|
|
||||||
|
let a = false;
|
||||||
switch (tagName) {
|
switch (tagName) {
|
||||||
case "textarea":
|
case "textarea":
|
||||||
input.val(answers.filter("[name$=" + suffix + "]").val());
|
a = answers.filter("[name$=" + suffix + "]");
|
||||||
|
if (a.length) input.val(a.val());
|
||||||
break;
|
break;
|
||||||
case "select":
|
case "select":
|
||||||
input.val(answers.filter("[name$=" + suffix + "]").find(":selected").val()).change();
|
a = answers.filter("[name$=" + suffix + "]").find(":selected");
|
||||||
|
if (a.length) input.val(a.val()).change();
|
||||||
break;
|
break;
|
||||||
case "input":
|
case "input":
|
||||||
switch (attributeType) {
|
switch (attributeType) {
|
||||||
case "text":
|
case "text":
|
||||||
case "number":
|
case "number":
|
||||||
input.val(answers.filter("[name$=" + suffix + "]").val());
|
a = answers.filter("[name$=" + suffix + "]")
|
||||||
|
if (a.length) input.val(a.val());
|
||||||
break;
|
break;
|
||||||
case "checkbox":
|
case "checkbox":
|
||||||
case "radio":
|
case "radio":
|
||||||
if (input.attr('value')) {
|
if (input.attr('value')) {
|
||||||
input.prop("checked", answers.filter("[name$=" + suffix + "][value=" + input.attr('value') + "]").prop("checked"));
|
a = answers.filter("[name$=" + suffix + "][value=" + input.attr('value') + "]")
|
||||||
|
if (a.length) input.prop("checked", a.prop("checked"));
|
||||||
} else {
|
} else {
|
||||||
input.prop("checked", answers.filter("[name$=" + suffix + "]").prop("checked"));
|
a = answers.filter("[name$=" + suffix + "]")
|
||||||
|
if (a.length) input.prop("checked", a.prop("checked"));
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
input.val(answers.filter("[name$=" + suffix + "]").val());
|
a = answers.filter("[name$=" + suffix + "]")
|
||||||
|
if (a.length) input.val(a.val());
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
input.val(answers.filter("[name$=" + suffix + "]").val());
|
a = answers.filter("[name$=" + suffix + "]")
|
||||||
|
if (a.length) input.val(a.val());
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
questions_toggle_dependent(true);
|
questions_toggle_dependent(true);
|
||||||
|
|||||||
Reference in New Issue
Block a user