mirror of
https://github.com/pretix/pretix.git
synced 2026-01-12 22:42:26 +00:00
Compare commits
7 Commits
quickstart
...
op-export-
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
833966a4cd | ||
|
|
d8d56ff020 | ||
|
|
44b3647689 | ||
|
|
818bb76e89 | ||
|
|
8c01cad06b | ||
|
|
86ca7c4440 | ||
|
|
d7b6856322 |
@@ -5,6 +5,7 @@ Resource description
|
||||
--------------------
|
||||
|
||||
Program times for products (items) that can be set in addition to event times, e.g. to display seperate schedules within an event.
|
||||
Note that ``program_times`` are not available for items inside event series.
|
||||
The program times resource contains the following public fields:
|
||||
|
||||
.. rst-class:: rest-resource-table
|
||||
|
||||
@@ -142,6 +142,7 @@ variations list of objects A list with o
|
||||
program_times list of objects A list with one object for each program time of this item.
|
||||
Can be empty. Only writable during creation,
|
||||
use separate endpoint to modify this later.
|
||||
Not available for items in event series.
|
||||
├ id integer Internal ID of the variation
|
||||
├ value multi-lingual string The "name" of the variation
|
||||
├ default_price money (string) The price set directly for this variation or ``null``
|
||||
@@ -243,6 +244,8 @@ Also note that ``variations``, ``bundles``, ``addons`` and ``program_times`` ar
|
||||
bundles, add-ons and program times please use the dedicated nested endpoints. By design this endpoint does not support ``PATCH`` and ``PUT``
|
||||
with nested ``variations``, ``bundles``, ``addons`` and/or ``program_times``.
|
||||
|
||||
``program_times`` is not available to items in event series.
|
||||
|
||||
Endpoints
|
||||
---------
|
||||
|
||||
|
||||
@@ -241,6 +241,12 @@ class ItemProgramTimeSerializer(serializers.ModelSerializer):
|
||||
if start > end:
|
||||
raise ValidationError(_("The program end must not be before the program start."))
|
||||
|
||||
event = self.context['event']
|
||||
if event.has_subevents:
|
||||
raise ValidationError({
|
||||
_("You cannot use program times on an event series.")
|
||||
})
|
||||
|
||||
return data
|
||||
|
||||
|
||||
|
||||
@@ -40,7 +40,7 @@ from django_filters.rest_framework import DjangoFilterBackend, FilterSet
|
||||
from django_scopes import scopes_disabled
|
||||
from rest_framework import viewsets
|
||||
from rest_framework.decorators import action
|
||||
from rest_framework.exceptions import PermissionDenied
|
||||
from rest_framework.exceptions import PermissionDenied, ValidationError
|
||||
from rest_framework.response import Response
|
||||
|
||||
from pretix.api.pagination import TotalOrderingFilter
|
||||
@@ -293,6 +293,8 @@ class ItemProgramTimeViewSet(viewsets.ModelViewSet):
|
||||
return get_object_or_404(Item, pk=self.kwargs['item'], event=self.request.event)
|
||||
|
||||
def get_queryset(self):
|
||||
if self.request.event.has_subevents:
|
||||
raise ValidationError('You cannot use program times on an event series.')
|
||||
return self.item.program_times.all()
|
||||
|
||||
def get_serializer_context(self):
|
||||
|
||||
@@ -610,7 +610,7 @@ class OrderListExporter(MultiSheetListExporter):
|
||||
headers.append(_('Attendee name') + ': ' + str(label))
|
||||
headers += [
|
||||
_('Attendee email'),
|
||||
_('Company'),
|
||||
_('Attendee company'),
|
||||
_('Address'),
|
||||
_('ZIP code'),
|
||||
_('City'),
|
||||
@@ -650,7 +650,7 @@ class OrderListExporter(MultiSheetListExporter):
|
||||
options[q.pk].append(o)
|
||||
headers.append(str(q.question))
|
||||
headers += [
|
||||
_('Company'),
|
||||
_('Invoice address company'),
|
||||
_('Invoice address name'),
|
||||
]
|
||||
if name_scheme and len(name_scheme['fields']) > 1:
|
||||
|
||||
@@ -990,10 +990,11 @@ class Event(EventMixin, LoggedModel):
|
||||
ia.bundled_variation = variation_map[ia.bundled_variation.pk]
|
||||
ia.save(force_insert=True)
|
||||
|
||||
for ipt in ItemProgramTime.objects.filter(item__event=other).prefetch_related('item'):
|
||||
ipt.pk = None
|
||||
ipt.item = item_map[ipt.item.pk]
|
||||
ipt.save(force_insert=True)
|
||||
if not self.has_subevents and not other.has_subevents:
|
||||
for ipt in ItemProgramTime.objects.filter(item__event=other).prefetch_related('item'):
|
||||
ipt.pk = None
|
||||
ipt.item = item_map[ipt.item.pk]
|
||||
ipt.save(force_insert=True)
|
||||
|
||||
quota_map = {}
|
||||
for q in Quota.objects.filter(event=other, subevent__isnull=True).prefetch_related('items', 'variations'):
|
||||
|
||||
@@ -2311,6 +2311,8 @@ class ItemProgramTime(models.Model):
|
||||
end = models.DateTimeField(verbose_name=_("End"))
|
||||
|
||||
def clean(self):
|
||||
if self.item.event.has_subevents:
|
||||
raise ValidationError(_("You cannot use program times on an event series."))
|
||||
self.clean_start_end(start=self.start, end=self.end)
|
||||
super().clean()
|
||||
|
||||
|
||||
@@ -374,6 +374,13 @@ class EventUpdateForm(I18nModelForm):
|
||||
super().__init__(*args, **kwargs)
|
||||
if not self.change_slug:
|
||||
self.fields['slug'].widget.attrs['readonly'] = 'readonly'
|
||||
|
||||
if self.instance.orders.exists():
|
||||
self.fields['currency'].disabled = True
|
||||
self.fields['currency'].help_text = _(
|
||||
'The currency cannot be changed because orders already exist.'
|
||||
)
|
||||
|
||||
self.fields['location'].widget.attrs['rows'] = '3'
|
||||
self.fields['location'].widget.attrs['placeholder'] = _(
|
||||
'Sample Conference Center\nHeidelberg, Germany'
|
||||
@@ -1860,11 +1867,7 @@ class QuickSetupForm(I18nForm):
|
||||
self.fields['payment_banktransfer_bank_details'].required = False
|
||||
for f in self.fields.values():
|
||||
if 'data-required-if' in f.widget.attrs:
|
||||
f.widget.attrs['data-required-if'] += ",#id_payment_banktransfer__enabled"
|
||||
|
||||
self.fields['payment_banktransfer_bank_details'].widget.attrs["data-required-if"] = (
|
||||
"#id_payment_banktransfer_bank_details_type_1,#id_payment_banktransfer__enabled"
|
||||
)
|
||||
del f.widget.attrs['data-required-if']
|
||||
|
||||
def clean(self):
|
||||
cleaned_data = super().clean()
|
||||
|
||||
@@ -858,50 +858,58 @@ class ReportExporter(ReportlabExportMixin, BaseExporter):
|
||||
|
||||
for c in currencies:
|
||||
c_head = f" [{c}]" if len(currencies) > 1 else ""
|
||||
story += [
|
||||
Spacer(0, 3 * mm),
|
||||
FontFallbackParagraph(_("Orders") + c_head, style_h2),
|
||||
Spacer(0, 3 * mm),
|
||||
*self._table_transactions(form_data, c),
|
||||
]
|
||||
s = self._table_transactions(form_data, c)
|
||||
if s:
|
||||
story += [
|
||||
Spacer(0, 3 * mm),
|
||||
FontFallbackParagraph(_("Orders") + c_head, style_h2),
|
||||
Spacer(0, 3 * mm),
|
||||
*s
|
||||
]
|
||||
|
||||
for c in currencies:
|
||||
c_head = f" [{c}]" if len(currencies) > 1 else ""
|
||||
story += [
|
||||
Spacer(0, 8 * mm),
|
||||
FontFallbackParagraph(_("Payments") + c_head, style_h2),
|
||||
Spacer(0, 3 * mm),
|
||||
*self._table_payments(form_data, c),
|
||||
]
|
||||
s = self._table_payments(form_data, c)
|
||||
if s:
|
||||
story += [
|
||||
Spacer(0, 8 * mm),
|
||||
FontFallbackParagraph(_("Payments") + c_head, style_h2),
|
||||
Spacer(0, 3 * mm),
|
||||
*s
|
||||
]
|
||||
|
||||
for c in currencies:
|
||||
c_head = f" [{c}]" if len(currencies) > 1 else ""
|
||||
story += [
|
||||
Spacer(0, 8 * mm),
|
||||
KeepTogether(
|
||||
[
|
||||
FontFallbackParagraph(_("Open items") + c_head, style_h2),
|
||||
Spacer(0, 3 * mm),
|
||||
*self._table_open_items(form_data, c),
|
||||
]
|
||||
),
|
||||
]
|
||||
s = self._table_open_items(form_data, c)
|
||||
if s:
|
||||
story += [
|
||||
Spacer(0, 8 * mm),
|
||||
KeepTogether(
|
||||
[
|
||||
FontFallbackParagraph(_("Open items") + c_head, style_h2),
|
||||
Spacer(0, 3 * mm),
|
||||
*s
|
||||
]
|
||||
),
|
||||
]
|
||||
if (
|
||||
self.is_multievent
|
||||
and self.events.count() == self.organizer.events.count()
|
||||
):
|
||||
for c in currencies:
|
||||
c_head = f" [{c}]" if len(currencies) > 1 else ""
|
||||
story += [
|
||||
Spacer(0, 8 * mm),
|
||||
KeepTogether(
|
||||
[
|
||||
FontFallbackParagraph(_("Gift cards") + c_head, style_h2),
|
||||
Spacer(0, 3 * mm),
|
||||
*self._table_gift_cards(form_data, c),
|
||||
]
|
||||
),
|
||||
]
|
||||
s = self._table_gift_cards(form_data, c)
|
||||
if s:
|
||||
story += [
|
||||
Spacer(0, 8 * mm),
|
||||
KeepTogether(
|
||||
[
|
||||
FontFallbackParagraph(_("Gift cards") + c_head, style_h2),
|
||||
Spacer(0, 3 * mm),
|
||||
*s,
|
||||
]
|
||||
),
|
||||
]
|
||||
|
||||
doc.build(story, canvasmaker=self.canvas_class(doc))
|
||||
f.seek(0)
|
||||
|
||||
@@ -23,7 +23,7 @@
|
||||
{% else %}
|
||||
<p>{% blocktrans trimmed %}
|
||||
After you submitted your order, we will redirect you to the payment service provider to complete your payment.
|
||||
You will then be redirected back here to get your tickets.
|
||||
You will then be redirected back here.
|
||||
{% endblocktrans %}</p>
|
||||
<dl class="dl-horizontal">
|
||||
<dt>{% trans "Payment method" %}</dt>
|
||||
|
||||
@@ -6,5 +6,5 @@
|
||||
{% bootstrap_form form layout='horizontal' %}
|
||||
<p class="help-block">{% blocktrans trimmed %}
|
||||
After you submitted your order, we will redirect you to the payment service provider to complete your payment.
|
||||
You will then be redirected back here to get your tickets.
|
||||
You will then be redirected back here.
|
||||
{% endblocktrans %}</p>
|
||||
|
||||
@@ -11,8 +11,8 @@
|
||||
|
||||
<p class="help-block">
|
||||
{% blocktrans trimmed %}
|
||||
After you submitted your order, we will redirect you to the payment service provider to complete your
|
||||
payment. You will then be redirected back here to get your tickets.
|
||||
After you submitted your order, we will redirect you to the payment service provider to complete your payment.
|
||||
You will then be redirected back here.
|
||||
{% endblocktrans %}
|
||||
</p>
|
||||
|
||||
|
||||
@@ -4,5 +4,5 @@
|
||||
{% endif %}
|
||||
<p class="help-block">{% blocktrans trimmed %}
|
||||
After you submitted your order, we will redirect you to the payment service provider to complete your payment.
|
||||
You will then be redirected back here to get your tickets.
|
||||
You will then be redirected back here.
|
||||
{% endblocktrans %}</p>
|
||||
|
||||
@@ -88,7 +88,7 @@
|
||||
</p>
|
||||
{% endif %}
|
||||
</div>
|
||||
{% elif not can_download and plugins_allow_ticket_download and ticket_download_date %}
|
||||
{% elif not can_download and plugins_allow_ticket_download and ticket_download_date and event.settings.ticket_download %}
|
||||
{% if order.status == 'p' %}
|
||||
<div class="alert alert-info info-download">
|
||||
{% blocktrans trimmed with date=ticket_download_date|date:"SHORT_DATE_FORMAT" %}
|
||||
|
||||
@@ -689,7 +689,7 @@ class EventIndex(EventViewMixin, EventListMixin, CartMixin, TemplateView):
|
||||
self._set_month_year()
|
||||
tz = self.request.event.timezone
|
||||
_, ndays = calendar.monthrange(self.year, self.month)
|
||||
before = datetime(self.year, self.month, 1, 0, 0, 0, tzinfo=tz) - timedelta(days=1)
|
||||
before = datetime(self.year, self.month, 1, 23, 59, 59, tzinfo=tz) - timedelta(days=1)
|
||||
after = datetime(self.year, self.month, ndays, 0, 0, 0, tzinfo=tz) + timedelta(days=1)
|
||||
|
||||
if self.request.event.settings.event_calendar_future_only:
|
||||
@@ -750,7 +750,7 @@ class EventIndex(EventViewMixin, EventListMixin, CartMixin, TemplateView):
|
||||
tz = self.request.event.timezone
|
||||
week = isoweek.Week(self.year, self.week)
|
||||
before = datetime(
|
||||
week.monday().year, week.monday().month, week.monday().day, 0, 0, 0, tzinfo=tz
|
||||
week.monday().year, week.monday().month, week.monday().day, 23, 59, 59, tzinfo=tz
|
||||
) - timedelta(days=1)
|
||||
after = datetime(
|
||||
week.sunday().year, week.sunday().month, week.sunday().day, 0, 0, 0, tzinfo=tz
|
||||
|
||||
@@ -768,7 +768,7 @@ class CalendarView(OrganizerViewMixin, EventListMixin, TemplateView):
|
||||
raise Http404()
|
||||
|
||||
tz = get_current_timezone()
|
||||
before = datetime(self.year, self.month, 1, 0, 0, 0, tzinfo=tz) - timedelta(days=1)
|
||||
before = datetime(self.year, self.month, 1, 23, 59, 59, tzinfo=tz) - timedelta(days=1)
|
||||
after = datetime(self.year, self.month, ndays, 0, 0, 0, tzinfo=tz) + timedelta(days=1)
|
||||
|
||||
ctx['date'] = date(self.year, self.month, 1)
|
||||
@@ -854,7 +854,7 @@ class WeekCalendarView(OrganizerViewMixin, EventListMixin, TemplateView):
|
||||
tz = get_current_timezone()
|
||||
week = isoweek.Week(self.year, self.week)
|
||||
before = datetime(
|
||||
week.monday().year, week.monday().month, week.monday().day, 0, 0, 0, tzinfo=tz,
|
||||
week.monday().year, week.monday().month, week.monday().day, 23, 59, 59, tzinfo=tz,
|
||||
) - timedelta(days=1)
|
||||
after = datetime(
|
||||
week.sunday().year, week.sunday().month, week.sunday().day, 0, 0, 0, tzinfo=tz,
|
||||
@@ -1001,7 +1001,7 @@ class DayCalendarView(OrganizerViewMixin, EventListMixin, TemplateView):
|
||||
|
||||
tz = get_current_timezone()
|
||||
before = datetime(
|
||||
self.date.year, self.date.month, self.date.day, 0, 0, 0, tzinfo=tz,
|
||||
self.date.year, self.date.month, self.date.day, 23, 59, 59, tzinfo=tz,
|
||||
) - timedelta(days=1)
|
||||
after = datetime(
|
||||
self.date.year, self.date.month, self.date.day, 0, 0, 0, tzinfo=tz,
|
||||
|
||||
@@ -415,24 +415,16 @@ var form_handlers = function (el) {
|
||||
|
||||
el.find("input[data-required-if], select[data-required-if], textarea[data-required-if]").each(function () {
|
||||
var dependent = $(this),
|
||||
dependencies = $($(this).attr("data-required-if")),
|
||||
dependency = $($(this).attr("data-required-if")),
|
||||
update = function (ev) {
|
||||
var enabled = true;
|
||||
dependencies.each(function () {
|
||||
var dependency = $(this);
|
||||
var e = (dependency.attr("type") === 'checkbox' || dependency.attr("type") === 'radio') ? dependency.prop('checked') : !!dependency.val();
|
||||
enabled = enabled && e;
|
||||
});
|
||||
var enabled = (dependency.attr("type") === 'checkbox' || dependency.attr("type") === 'radio') ? dependency.prop('checked') : !!dependency.val();
|
||||
dependent.prop('required', enabled).closest('.form-group').toggleClass('required', enabled).find('.optional').stop().animate({
|
||||
'opacity': enabled ? 0 : 1
|
||||
}, ev ? 500 : 1);
|
||||
};
|
||||
update();
|
||||
dependencies.each(function () {
|
||||
var dependency = $(this);
|
||||
dependency.closest('.form-group').find('input[name=' + dependency.attr("name") + ']').on("change", update);
|
||||
dependency.closest('.form-group').find('input[name=' + dependency.attr("name") + ']').on("dp.change", update);
|
||||
});
|
||||
dependency.closest('.form-group').find('input[name=' + dependency.attr("name") + ']').on("change", update);
|
||||
dependency.closest('.form-group').find('input[name=' + dependency.attr("name") + ']').on("dp.change", update);
|
||||
});
|
||||
|
||||
el.find("div.scrolling-choice:not(.no-search)").each(function () {
|
||||
|
||||
@@ -514,17 +514,13 @@ $(function () {
|
||||
$("input[data-required-if], select[data-required-if], textarea[data-required-if]").each(function () {
|
||||
var dependent = $(this),
|
||||
dependentLabel = $("label[for="+this.id+"]"),
|
||||
dependencies = $($(this).attr("data-required-if")),
|
||||
dependency = $($(this).attr("data-required-if")),
|
||||
update = function (ev) {
|
||||
var enabled = true;
|
||||
dependencies.each(function () {
|
||||
var dependency = $(this);
|
||||
var e = (dependency.attr("type") === 'checkbox' || dependency.attr("type") === 'radio') ? dependency.prop('checked') : !!dependency.val();
|
||||
enabled = enabled && e;
|
||||
});
|
||||
var enabled = (dependency.attr("type") === 'checkbox' || dependency.attr("type") === 'radio') ? dependency.prop('checked') : !!dependency.val();
|
||||
if (!dependent.is("[data-no-required-attr]")) {
|
||||
dependent.prop('required', enabled);
|
||||
}
|
||||
dependent.closest('.form-group').toggleClass('required', enabled);
|
||||
if (enabled) {
|
||||
dependentLabel.append('<i class="label-required">' + gettext('required') + '</i>');
|
||||
}
|
||||
@@ -533,11 +529,8 @@ $(function () {
|
||||
}
|
||||
};
|
||||
update();
|
||||
dependencies.each(function () {
|
||||
var dependency = $(this);
|
||||
dependency.closest('.form-group').find('input[name=' + dependency.attr("name") + ']').on("change", update);
|
||||
dependency.closest('.form-group').find('input[name=' + dependency.attr("name") + ']').on("dp.change", update);
|
||||
});
|
||||
dependency.closest('.form-group').find('input[name=' + dependency.attr("name") + ']').on("change", update);
|
||||
dependency.closest('.form-group').find('input[name=' + dependency.attr("name") + ']').on("dp.change", update);
|
||||
});
|
||||
|
||||
$("input[data-display-dependency], div[data-display-dependency], select[data-display-dependency], textarea[data-display-dependency]").each(function () {
|
||||
|
||||
Reference in New Issue
Block a user