forked from CGM_Public/pretix_original
Compare commits
9 Commits
fix-free-p
...
fix-api-op
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
c25ba29efe | ||
|
|
9d30034754 | ||
|
|
ec2da30c74 | ||
|
|
f3583488ef | ||
|
|
57ee2280aa | ||
|
|
75c069111e | ||
|
|
54a4631e22 | ||
|
|
8eaa8999e5 | ||
|
|
979e02ec73 |
@@ -19,6 +19,7 @@ If you want to **create** a plugin, please go to the
|
||||
certificates
|
||||
digital
|
||||
exhibitors
|
||||
shipping
|
||||
imported_secrets
|
||||
webinar
|
||||
presale-saml
|
||||
|
||||
235
doc/plugins/shipping.rst
Normal file
235
doc/plugins/shipping.rst
Normal file
@@ -0,0 +1,235 @@
|
||||
Shipping
|
||||
========
|
||||
|
||||
The shipping plugin provides a HTTP API that exposes the various layouts used to generate PDF badges.
|
||||
|
||||
Shipping address resource
|
||||
-------------------------
|
||||
|
||||
The shipping address resource contains the following public fields:
|
||||
|
||||
.. rst-class:: rest-resource-table
|
||||
|
||||
===================================== ========================== =======================================================
|
||||
Field Type Description
|
||||
===================================== ========================== =======================================================
|
||||
company string Customer company name
|
||||
name string Customer name
|
||||
street string Customer street
|
||||
zipcode string Customer ZIP code
|
||||
city string Customer city
|
||||
country string Customer country code
|
||||
state string Customer state (ISO 3166-2 code). Only supported in
|
||||
AU, BR, CA, CN, MY, MX, and US.
|
||||
gift boolean Request by customer to not disclose prices in the shipping
|
||||
===================================== ========================== =======================================================
|
||||
|
||||
Shipping status resource
|
||||
------------------------
|
||||
|
||||
The shipping status resource contains the following public fields:
|
||||
|
||||
.. rst-class:: rest-resource-table
|
||||
|
||||
===================================== ========================== =======================================================
|
||||
Field Type Description
|
||||
===================================== ========================== =======================================================
|
||||
method integer Internal ID of shipping method
|
||||
status string Status, one of ``"new"`` or ``"shipped"``
|
||||
method_type string Method type, one of ``"ship"``, ``"online"``, or ``"collect"``
|
||||
===================================== ========================== =======================================================
|
||||
|
||||
Print job resource
|
||||
------------------
|
||||
|
||||
The print job resource contains the following public fields:
|
||||
|
||||
.. rst-class:: rest-resource-table
|
||||
|
||||
===================================== ========================== =======================================================
|
||||
Field Type Description
|
||||
===================================== ========================== =======================================================
|
||||
code string Order code of the ticket order
|
||||
event string Event slug
|
||||
status string Status, one of ``"new"`` or ``"shipped"``
|
||||
method string Method type, one of ``"ship"``, ``"online"``, or ``"collect"``
|
||||
===================================== ========================== =======================================================
|
||||
|
||||
Endpoints
|
||||
---------
|
||||
|
||||
.. http:get:: /api/v1/organizers/(organizer)/events/(event)/orders/(code)/shippingaddress/
|
||||
|
||||
Returns the shipping address of an order
|
||||
|
||||
**Example request**:
|
||||
|
||||
.. sourcecode:: http
|
||||
|
||||
GET /api/v1/organizers/bigevents/events/democon/orders/ABC12/shippingaddress/ HTTP/1.1
|
||||
Host: pretix.eu
|
||||
Accept: application/json, text/javascript
|
||||
|
||||
**Example response**:
|
||||
|
||||
.. sourcecode:: http
|
||||
|
||||
HTTP/1.1 200 OK
|
||||
Vary: Accept
|
||||
Content-Type: text/javascript
|
||||
|
||||
{
|
||||
"company": "ACME Corp",
|
||||
"name": "John Doe",
|
||||
"street": "Sesame Street 12\nAp. 5",
|
||||
"zipcode": "12345",
|
||||
"city": "Berlin",
|
||||
"country": "DE",
|
||||
"state": "",
|
||||
"gift": false
|
||||
}
|
||||
|
||||
:param organizer: The ``slug`` field of a valid organizer
|
||||
:param event: The ``slug`` field of a valid event
|
||||
:param order: The ``code`` field of a valid order
|
||||
:statuscode 200: no error
|
||||
:statuscode 401: Authentication failure
|
||||
:statuscode 403: The requested organizer does not exist **or** you have no permission to view it.
|
||||
:statuscode 404: The order does not exist or no shipping address is attached.
|
||||
|
||||
|
||||
.. http:get:: /api/v1/organizers/(organizer)/events/(event)/orders/(code)/shippingaddress/
|
||||
|
||||
Returns the shipping status of an order
|
||||
|
||||
**Example request**:
|
||||
|
||||
.. sourcecode:: http
|
||||
|
||||
GET /api/v1/organizers/bigevents/events/democon/orders/ABC12/shippingstatus/ HTTP/1.1
|
||||
Host: pretix.eu
|
||||
Accept: application/json, text/javascript
|
||||
|
||||
**Example response**:
|
||||
|
||||
.. sourcecode:: http
|
||||
|
||||
HTTP/1.1 200 OK
|
||||
Vary: Accept
|
||||
Content-Type: text/javascript
|
||||
|
||||
{
|
||||
"method": 23,
|
||||
"method_type": "ship",
|
||||
"status": "new"
|
||||
}
|
||||
|
||||
:param organizer: The ``slug`` field of a valid organizer
|
||||
:param event: The ``slug`` field of a valid event
|
||||
:param order: The ``code`` field of a valid order
|
||||
:statuscode 200: no error
|
||||
:statuscode 401: Authentication failure
|
||||
:statuscode 403: The requested organizer does not exist **or** you have no permission to view it.
|
||||
:statuscode 404: The order does not exist or no shipping address is attached.
|
||||
|
||||
.. http:get:: /api/v1/organizers/(organizer)/printjobs/
|
||||
|
||||
Returns a list of ticket orders, only useful with some query filters
|
||||
|
||||
**Example request**:
|
||||
|
||||
.. sourcecode:: http
|
||||
|
||||
GET /api/v1/organizers/bigevents/printjobs/?method=ship&status=new HTTP/1.1
|
||||
Host: pretix.eu
|
||||
Accept: application/json, text/javascript
|
||||
|
||||
**Example response**:
|
||||
|
||||
.. sourcecode:: http
|
||||
|
||||
HTTP/1.1 200 OK
|
||||
Vary: Accept
|
||||
Content-Type: text/javascript
|
||||
|
||||
{
|
||||
"count": 1,
|
||||
"next": null,
|
||||
"previous": null,
|
||||
"results": [
|
||||
{
|
||||
"event": "democon",
|
||||
"order": "ABC12",
|
||||
"method": "ship",
|
||||
"status": "new"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
:query string method: Filter by response field ``method`` (can be passed multiple times)
|
||||
:query string status: Filter by response field ``status``
|
||||
:query string event: Filter by response field ``event``
|
||||
:param organizer: The ``slug`` field of a valid organizer
|
||||
:param event: The ``slug`` field of a valid event
|
||||
:statuscode 200: no error
|
||||
:statuscode 401: Authentication failure
|
||||
:statuscode 403: The requested organizer does not exist **or** you have no permission to view it.
|
||||
|
||||
.. http:get:: /api/v1/organizers/(organizer)/printjobs/poll/
|
||||
|
||||
Returns the PDF file for the next job to print.
|
||||
|
||||
**Example request**:
|
||||
|
||||
.. sourcecode:: http
|
||||
|
||||
GET /api/v1/organizers/bigevents/printjobs/poll/?method=ship&status=new HTTP/1.1
|
||||
Host: pretix.eu
|
||||
Accept: application/json, text/javascript
|
||||
|
||||
**Example response**:
|
||||
|
||||
.. sourcecode:: http
|
||||
|
||||
HTTP/1.1 200 OK
|
||||
Vary: Accept
|
||||
Content-Type: application/pdf
|
||||
X-Pretix-Order-Code: ABC12
|
||||
|
||||
...
|
||||
|
||||
:query string method: Filter by response field ``method`` (can be passed multiple times)
|
||||
:query string status: Filter by response field ``status``
|
||||
:query string event: Filter by response field ``event``
|
||||
:param organizer: The ``slug`` field of a valid organizer
|
||||
:param event: The ``slug`` field of a valid event
|
||||
:statuscode 200: no error
|
||||
:statuscode 401: Authentication failure
|
||||
:statuscode 403: The requested organizer does not exist **or** you have no permission to view it.
|
||||
|
||||
.. http:post:: /api/v1/organizers/(organizer)/printjobs/(order)/ack/
|
||||
|
||||
Change an order's status to "shipped".
|
||||
|
||||
**Example request**:
|
||||
|
||||
.. sourcecode:: http
|
||||
|
||||
POST /api/v1/organizers/bigevents/printjobs/ABC12/ack/ HTTP/1.1
|
||||
Host: pretix.eu
|
||||
Accept: application/json, text/javascript
|
||||
|
||||
**Example response**:
|
||||
|
||||
.. sourcecode:: http
|
||||
|
||||
HTTP/1.1 204 No Content
|
||||
Vary: Accept
|
||||
|
||||
:param organizer: The ``slug`` field of a valid organizer
|
||||
:param event: The ``slug`` field of a valid event
|
||||
:param order: The ``code`` field of a valid order
|
||||
:statuscode 200: no error
|
||||
:statuscode 401: Authentication failure
|
||||
:statuscode 403: The requested organizer does not exist **or** you have no permission to view it.
|
||||
:statuscode 404: The order does not exist.
|
||||
@@ -0,0 +1,33 @@
|
||||
# Generated by Django 3.2.12 on 2022-06-15 08:10
|
||||
|
||||
import django.db.models.deletion
|
||||
import i18nfield.fields
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('pretixbase', '0216_checkin_forced_sent'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.CreateModel(
|
||||
name='OrganizerFooterLink',
|
||||
fields=[
|
||||
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False)),
|
||||
('label', i18nfield.fields.I18nCharField(max_length=200)),
|
||||
('url', models.URLField()),
|
||||
('organizer', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='footer_links', to='pretixbase.organizer')),
|
||||
],
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name='EventFooterLink',
|
||||
fields=[
|
||||
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False)),
|
||||
('label', i18nfield.fields.I18nCharField(max_length=200)),
|
||||
('url', models.URLField()),
|
||||
('event', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='footer_links', to='pretixbase.event')),
|
||||
],
|
||||
),
|
||||
]
|
||||
@@ -718,6 +718,11 @@ class Event(EventMixin, LoggedModel):
|
||||
self.save()
|
||||
self.log_action('pretix.object.cloned', data={'source': other.slug, 'source_id': other.pk})
|
||||
|
||||
for fl in EventFooterLink.objects.filter(event=other):
|
||||
fl.pk = None
|
||||
fl.event = self
|
||||
fl.save(force_insert=True)
|
||||
|
||||
tax_map = {}
|
||||
for t in other.tax_rules.all():
|
||||
tax_map[t.pk] = t
|
||||
@@ -1612,3 +1617,25 @@ class SubEventMetaValue(LoggedModel):
|
||||
super().save(*args, **kwargs)
|
||||
if self.subevent:
|
||||
self.subevent.event.cache.clear()
|
||||
|
||||
|
||||
class EventFooterLink(models.Model):
|
||||
"""
|
||||
A footer link assigned to an event.
|
||||
"""
|
||||
event = models.ForeignKey('Event', on_delete=models.CASCADE, related_name='footer_links')
|
||||
label = I18nCharField(
|
||||
max_length=200,
|
||||
verbose_name=_("Link text"),
|
||||
)
|
||||
url = models.URLField(
|
||||
verbose_name=_("Link URL"),
|
||||
)
|
||||
|
||||
def delete(self, *args, **kwargs):
|
||||
super().delete(*args, **kwargs)
|
||||
self.event.cache.clear()
|
||||
|
||||
def save(self, *args, **kwargs):
|
||||
super().save(*args, **kwargs)
|
||||
self.event.cache.clear()
|
||||
|
||||
@@ -46,6 +46,7 @@ from django.utils.crypto import get_random_string
|
||||
from django.utils.functional import cached_property
|
||||
from django.utils.timezone import get_current_timezone, make_aware, now
|
||||
from django.utils.translation import gettext_lazy as _
|
||||
from i18nfield.fields import I18nCharField
|
||||
|
||||
from pretix.base.models.base import LoggedModel
|
||||
from pretix.base.validators import OrganizerSlugBanlistValidator
|
||||
@@ -464,3 +465,25 @@ class TeamAPIToken(models.Model):
|
||||
return self.get_events_with_any_permission()
|
||||
else:
|
||||
return self.team.organizer.events.none()
|
||||
|
||||
|
||||
class OrganizerFooterLink(models.Model):
|
||||
"""
|
||||
A footer link assigned to an organizer.
|
||||
"""
|
||||
organizer = models.ForeignKey('Organizer', on_delete=models.CASCADE, related_name='footer_links')
|
||||
label = I18nCharField(
|
||||
max_length=200,
|
||||
verbose_name=_("Link text"),
|
||||
)
|
||||
url = models.URLField(
|
||||
verbose_name=_("Link URL"),
|
||||
)
|
||||
|
||||
def delete(self, *args, **kwargs):
|
||||
super().delete(*args, **kwargs)
|
||||
self.organizer.cache.clear()
|
||||
|
||||
def save(self, *args, **kwargs):
|
||||
super().save(*args, **kwargs)
|
||||
self.organizer.cache.clear()
|
||||
|
||||
@@ -2317,6 +2317,7 @@ class OrderChangeManager:
|
||||
self._check_and_lock_memberships()
|
||||
try:
|
||||
self._perform_operations()
|
||||
self.order.refresh_from_db()
|
||||
except TaxRule.SaleNotAllowed:
|
||||
raise OrderError(self.error_messages['tax_rule_country_blocked'])
|
||||
self._recalculate_total_and_payment_fee()
|
||||
|
||||
@@ -41,7 +41,9 @@ from django.conf import settings
|
||||
from django.core.exceptions import ValidationError
|
||||
from django.core.validators import validate_email
|
||||
from django.db.models import Prefetch, Q, prefetch_related_objects
|
||||
from django.forms import CheckboxSelectMultiple, formset_factory
|
||||
from django.forms import (
|
||||
CheckboxSelectMultiple, formset_factory, inlineformset_factory,
|
||||
)
|
||||
from django.urls import reverse
|
||||
from django.utils.functional import cached_property
|
||||
from django.utils.html import escape
|
||||
@@ -58,7 +60,7 @@ from pretix.base.channels import get_all_sales_channels
|
||||
from pretix.base.email import get_available_placeholders
|
||||
from pretix.base.forms import I18nModelForm, PlaceholderValidator, SettingsForm
|
||||
from pretix.base.models import Event, Organizer, TaxRule, Team
|
||||
from pretix.base.models.event import EventMetaValue, SubEvent
|
||||
from pretix.base.models.event import EventFooterLink, EventMetaValue, SubEvent
|
||||
from pretix.base.reldate import RelativeDateField, RelativeDateTimeField
|
||||
from pretix.base.settings import (
|
||||
PERSON_NAME_SCHEMES, PERSON_NAME_TITLE_GROUPS, validate_event_settings,
|
||||
@@ -1484,3 +1486,25 @@ ConfirmTextFormset = formset_factory(
|
||||
formset=BaseConfirmTextFormSet,
|
||||
can_order=True, can_delete=True, extra=0
|
||||
)
|
||||
|
||||
|
||||
class EventFooterLinkForm(I18nModelForm):
|
||||
class Meta:
|
||||
model = EventFooterLink
|
||||
fields = ('label', 'url')
|
||||
|
||||
|
||||
class BaseEventFooterLinkFormSet(I18nFormSetMixin, forms.BaseInlineFormSet):
|
||||
def __init__(self, *args, **kwargs):
|
||||
event = kwargs.pop('event', None)
|
||||
if event:
|
||||
kwargs['locales'] = event.settings.get('locales')
|
||||
super().__init__(*args, **kwargs)
|
||||
|
||||
|
||||
EventFooterLinkFormset = inlineformset_factory(
|
||||
Event, EventFooterLink,
|
||||
EventFooterLinkForm,
|
||||
formset=BaseEventFooterLinkFormSet,
|
||||
can_order=False, can_delete=True, extra=0
|
||||
)
|
||||
|
||||
@@ -39,12 +39,13 @@ from django import forms
|
||||
from django.conf import settings
|
||||
from django.core.exceptions import ValidationError
|
||||
from django.db.models import Q
|
||||
from django.forms import inlineformset_factory
|
||||
from django.forms.utils import ErrorDict
|
||||
from django.utils.crypto import get_random_string
|
||||
from django.utils.safestring import mark_safe
|
||||
from django.utils.translation import gettext_lazy as _, pgettext_lazy
|
||||
from django_scopes.forms import SafeModelMultipleChoiceField
|
||||
from i18nfield.forms import I18nFormField, I18nTextarea
|
||||
from i18nfield.forms import I18nFormField, I18nFormSetMixin, I18nTextarea
|
||||
from phonenumber_field.formfields import PhoneNumberField
|
||||
from pytz import common_timezones
|
||||
|
||||
@@ -60,6 +61,7 @@ from pretix.base.models import (
|
||||
Customer, Device, EventMetaProperty, Gate, GiftCard, Membership,
|
||||
MembershipType, Organizer, Team,
|
||||
)
|
||||
from pretix.base.models.organizer import OrganizerFooterLink
|
||||
from pretix.base.settings import PERSON_NAME_SCHEMES, PERSON_NAME_TITLE_GROUPS
|
||||
from pretix.control.forms import ExtFileField, SplitDateTimeField
|
||||
from pretix.control.forms.event import (
|
||||
@@ -682,3 +684,25 @@ class MembershipUpdateForm(forms.ModelForm):
|
||||
titles=self.instance.customer.organizer.settings.name_scheme_titles,
|
||||
label=_('Attendee name'),
|
||||
)
|
||||
|
||||
|
||||
class OrganizerFooterLinkForm(I18nModelForm):
|
||||
class Meta:
|
||||
model = OrganizerFooterLink
|
||||
fields = ('label', 'url')
|
||||
|
||||
|
||||
class BaseOrganizerFooterLinkFormSet(I18nFormSetMixin, forms.BaseInlineFormSet):
|
||||
def __init__(self, *args, **kwargs):
|
||||
organizer = kwargs.pop('organizer', None)
|
||||
if organizer:
|
||||
kwargs['locales'] = organizer.settings.get('locales')
|
||||
super().__init__(*args, **kwargs)
|
||||
|
||||
|
||||
OrganizerFooterLinkFormset = inlineformset_factory(
|
||||
Organizer, OrganizerFooterLink,
|
||||
OrganizerFooterLinkForm,
|
||||
formset=BaseOrganizerFooterLinkFormSet,
|
||||
can_order=False, can_delete=True, extra=0
|
||||
)
|
||||
|
||||
@@ -314,6 +314,7 @@ def pretixcontrol_logentry_display(sender: Event, logentry: LogEntry, **kwargs):
|
||||
'pretix.object.cloned': _('This object has been created by cloning.'),
|
||||
'pretix.organizer.changed': _('The organizer has been changed.'),
|
||||
'pretix.organizer.settings': _('The organizer settings have been changed.'),
|
||||
'pretix.organizer.footerlinks.changed': _('The footer links have been changed.'),
|
||||
'pretix.giftcards.acceptance.added': _('Gift card acceptance for another organizer has been added.'),
|
||||
'pretix.giftcards.acceptance.removed': _('Gift card acceptance for another organizer has been removed.'),
|
||||
'pretix.webhook.created': _('The webhook has been created.'),
|
||||
@@ -468,6 +469,7 @@ def pretixcontrol_logentry_display(sender: Event, logentry: LogEntry, **kwargs):
|
||||
'pretix.event.testmode.deactivated': _('The test mode has been disabled.'),
|
||||
'pretix.event.added': _('The event has been created.'),
|
||||
'pretix.event.changed': _('The event details have been changed.'),
|
||||
'pretix.event.footerlinks.changed': _('The footer links have been changed.'),
|
||||
'pretix.event.question.option.added': _('An answer option has been added to the question.'),
|
||||
'pretix.event.question.option.deleted': _('An answer option has been removed from the question.'),
|
||||
'pretix.event.question.option.changed': _('An answer option has been changed.'),
|
||||
|
||||
@@ -69,7 +69,8 @@
|
||||
</label>
|
||||
<div class="col-md-9">
|
||||
<div class="checkbox">
|
||||
<label><input type="checkbox" checked="checked" disabled="disabled"> {% trans "Ask and require input" %}</label>
|
||||
<label><input type="checkbox" checked="checked"
|
||||
disabled="disabled"> {% trans "Ask and require input" %}</label>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -81,7 +82,8 @@
|
||||
</label>
|
||||
<div class="col-md-9 static-form-row">
|
||||
<p>
|
||||
<a href="{% url "control:event.settings.invoice" event=request.event.slug organizer=request.organizer.slug %}#tab-0-1-open" target="_blank">
|
||||
<a href="{% url "control:event.settings.invoice" event=request.event.slug organizer=request.organizer.slug %}#tab-0-1-open"
|
||||
target="_blank">
|
||||
{% trans "See invoice settings" %}
|
||||
</a>
|
||||
</p>
|
||||
@@ -101,7 +103,8 @@
|
||||
</label>
|
||||
<div class="col-md-9 static-form-row">
|
||||
<p>
|
||||
<a href="{% url "control:event.items.questions" event=request.event.slug organizer=request.organizer.slug %}" target="_blank">
|
||||
<a href="{% url "control:event.items.questions" event=request.event.slug organizer=request.organizer.slug %}"
|
||||
target="_blank">
|
||||
{% trans "Manage questions" %}
|
||||
</a>
|
||||
</p>
|
||||
@@ -232,10 +235,74 @@
|
||||
{% bootstrap_field sform.display_net_prices layout="control" %}
|
||||
{% bootstrap_field sform.show_variations_expanded layout="control" %}
|
||||
{% bootstrap_field sform.hide_sold_out layout="control" %}
|
||||
{% url "control:organizer.edit" organizer=request.organizer.slug as org_url %}
|
||||
{% propagated request.event org_url "meta_noindex" %}
|
||||
{% bootstrap_field sform.meta_noindex layout="control" %}
|
||||
{% endpropagated %}
|
||||
|
||||
<div class="form-group">
|
||||
<label class="col-md-3 control-label">
|
||||
{% trans "Footer links" %}<br>
|
||||
<span class="optional">{% trans "Optional" %}</span>
|
||||
</label>
|
||||
<div class="col-md-9">
|
||||
<p class="help-block">
|
||||
{% blocktrans trimmed %}
|
||||
These links will be shown in the footer of your ticket shop. You could
|
||||
for example link your terms of service here. Your contact address, imprint, and privacy
|
||||
policy will be linked automatically (if you configured them), so you do not need to add
|
||||
them here.
|
||||
{% endblocktrans %}
|
||||
</p>
|
||||
<div class="formset" data-formset data-formset-prefix="{{ footer_links_formset.prefix }}">
|
||||
{{ footer_links_formset.management_form }}
|
||||
{% bootstrap_formset_errors footer_links_formset %}
|
||||
<div data-formset-body>
|
||||
{% for form in footer_links_formset %}
|
||||
<div class="row formset-row" data-formset-form>
|
||||
<div class="sr-only">
|
||||
{{ form.id }}
|
||||
{% bootstrap_field form.DELETE form_group_class="" layout="inline" %}
|
||||
</div>
|
||||
<div class="col-md-5">
|
||||
{% bootstrap_form_errors form %}
|
||||
{% bootstrap_field form.label layout='inline' form_group_class="" %}
|
||||
</div>
|
||||
<div class="col-md-5">
|
||||
{% bootstrap_field form.url layout='inline' form_group_class="" %}
|
||||
</div>
|
||||
<div class="col-md-2 text-right flip">
|
||||
<button type="button" class="btn btn-danger" data-formset-delete-button>
|
||||
<i class="fa fa-trash"></i></button>
|
||||
</div>
|
||||
</div>
|
||||
{% endfor %}
|
||||
</div>
|
||||
<script type="form-template" data-formset-empty-form>
|
||||
{% escapescript %}
|
||||
<div class="row formset-row" data-formset-form>
|
||||
<div class="sr-only">
|
||||
{{ footer_links_formset.empty_form.id }}
|
||||
{% bootstrap_field footer_links_formset.empty_form.DELETE form_group_class="" layout="inline" %}
|
||||
</div>
|
||||
<div class="col-md-5">
|
||||
{% bootstrap_field footer_links_formset.empty_form.label layout='inline' form_group_class="" %}
|
||||
</div>
|
||||
<div class="col-md-5">
|
||||
{% bootstrap_field footer_links_formset.empty_form.url layout='inline' form_group_class="" %}
|
||||
</div>
|
||||
<div class="col-md-2 text-right flip">
|
||||
|
||||
<button type="button" class="btn btn-danger" data-formset-delete-button>
|
||||
<i class="fa fa-trash"></i></button>
|
||||
</div>
|
||||
</div>
|
||||
{% endescapescript %}
|
||||
</script>
|
||||
<p>
|
||||
<button type="button" class="btn btn-default" data-formset-add>
|
||||
<i class="fa fa-plus"></i> {% trans "Add link" %}</button>
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{% if sform.frontpage_subevent_ordering %}
|
||||
{% bootstrap_field sform.frontpage_subevent_ordering layout="control" %}
|
||||
{% endif %}
|
||||
@@ -245,6 +312,11 @@
|
||||
{% if sform.event_list_available_only %}
|
||||
{% bootstrap_field sform.event_list_available_only layout="control" %}
|
||||
{% endif %}
|
||||
|
||||
{% url "control:organizer.edit" organizer=request.organizer.slug as org_url %}
|
||||
{% propagated request.event org_url "meta_noindex" %}
|
||||
{% bootstrap_field sform.meta_noindex layout="control" %}
|
||||
{% endpropagated %}
|
||||
</fieldset>
|
||||
<fieldset>
|
||||
<legend>{% trans "Cart" %}</legend>
|
||||
@@ -262,13 +334,15 @@
|
||||
</div>
|
||||
<div class="alert alert-info">
|
||||
{% blocktrans trimmed %}
|
||||
The waiting list determines availability mainly based on quotas. If you use a seating plan and your
|
||||
The waiting list determines availability mainly based on quotas. If you use a seating plan and
|
||||
your
|
||||
number of available seats is less than the available quota, you might run into situations where
|
||||
people are sent an email from the waiting list but still are unable to book a seat.
|
||||
{% endblocktrans %}
|
||||
<strong>
|
||||
{% blocktrans trimmed %}
|
||||
Specifically, this means the waiting list is not safe to use together with the minimum distance
|
||||
Specifically, this means the waiting list is not safe to use together with the minimum
|
||||
distance
|
||||
feature of our seating plan module.
|
||||
{% endblocktrans %}
|
||||
</strong>
|
||||
|
||||
@@ -50,6 +50,77 @@
|
||||
{% bootstrap_field sform.event_list_availability layout="control" %}
|
||||
{% bootstrap_field sform.organizer_link_back layout="control" %}
|
||||
{% bootstrap_field sform.meta_noindex layout="control" %}
|
||||
<div class="form-group">
|
||||
<label class="col-md-3 control-label">
|
||||
{% trans "Footer links" %}<br>
|
||||
<span class="optional">{% trans "Optional" %}</span>
|
||||
</label>
|
||||
<div class="col-md-9">
|
||||
<p class="help-block">
|
||||
{% blocktrans trimmed %}
|
||||
These links will be shown in the footer of your ticket shop. You could
|
||||
for example link your terms of service here. Your contact address, imprint, and privacy
|
||||
policy will be linked automatically (if you configured them), so you do not need to add
|
||||
them here.
|
||||
{% endblocktrans %}
|
||||
</p>
|
||||
<p class="help-block">
|
||||
{% blocktrans trimmed %}
|
||||
The links you configure here will also be shown on all of your events.
|
||||
{% endblocktrans %}
|
||||
</p>
|
||||
<div class="formset" data-formset data-formset-prefix="{{ footer_links_formset.prefix }}">
|
||||
{{ footer_links_formset.management_form }}
|
||||
{% bootstrap_formset_errors footer_links_formset %}
|
||||
<div data-formset-body>
|
||||
{% for form in footer_links_formset %}
|
||||
<div class="row formset-row" data-formset-form>
|
||||
<div class="sr-only">
|
||||
{{ form.id }}
|
||||
{% bootstrap_field form.DELETE form_group_class="" layout="inline" %}
|
||||
</div>
|
||||
<div class="col-md-5">
|
||||
{% bootstrap_form_errors form %}
|
||||
{% bootstrap_field form.label layout='inline' form_group_class="" %}
|
||||
</div>
|
||||
<div class="col-md-5">
|
||||
{% bootstrap_field form.url layout='inline' form_group_class="" %}
|
||||
</div>
|
||||
<div class="col-md-2 text-right flip">
|
||||
<button type="button" class="btn btn-danger" data-formset-delete-button>
|
||||
<i class="fa fa-trash"></i></button>
|
||||
</div>
|
||||
</div>
|
||||
{% endfor %}
|
||||
</div>
|
||||
<script type="form-template" data-formset-empty-form>
|
||||
{% escapescript %}
|
||||
<div class="row formset-row" data-formset-form>
|
||||
<div class="sr-only">
|
||||
{{ footer_links_formset.empty_form.id }}
|
||||
{% bootstrap_field footer_links_formset.empty_form.DELETE form_group_class="" layout="inline" %}
|
||||
</div>
|
||||
<div class="col-md-5">
|
||||
{% bootstrap_field footer_links_formset.empty_form.label layout='inline' form_group_class="" %}
|
||||
</div>
|
||||
<div class="col-md-5">
|
||||
{% bootstrap_field footer_links_formset.empty_form.url layout='inline' form_group_class="" %}
|
||||
</div>
|
||||
<div class="col-md-2 text-right flip">
|
||||
|
||||
<button type="button" class="btn btn-danger" data-formset-delete-button>
|
||||
<i class="fa fa-trash"></i></button>
|
||||
</div>
|
||||
</div>
|
||||
{% endescapescript %}
|
||||
</script>
|
||||
<p>
|
||||
<button type="button" class="btn btn-default" data-formset-add>
|
||||
<i class="fa fa-plus"></i> {% trans "Add link" %}</button>
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</fieldset>
|
||||
<fieldset>
|
||||
<legend>{% trans "Localization" %}</legend>
|
||||
|
||||
@@ -74,9 +74,9 @@ from pretix.base.signals import register_ticket_outputs
|
||||
from pretix.base.templatetags.rich_text import markdown_compile_email
|
||||
from pretix.control.forms.event import (
|
||||
CancelSettingsForm, CommentForm, ConfirmTextFormset, EventDeleteForm,
|
||||
EventMetaValueForm, EventSettingsForm, EventUpdateForm,
|
||||
InvoiceSettingsForm, ItemMetaPropertyForm, MailSettingsForm,
|
||||
PaymentSettingsForm, ProviderForm, QuickSetupForm,
|
||||
EventFooterLinkFormset, EventMetaValueForm, EventSettingsForm,
|
||||
EventUpdateForm, InvoiceSettingsForm, ItemMetaPropertyForm,
|
||||
MailSettingsForm, PaymentSettingsForm, ProviderForm, QuickSetupForm,
|
||||
QuickSetupProductFormSet, TaxRuleForm, TaxRuleLineFormSet,
|
||||
TicketSettingsForm, WidgetCodeForm,
|
||||
)
|
||||
@@ -186,6 +186,7 @@ class EventUpdate(DecoupleMixin, EventSettingsViewMixin, EventPermissionRequired
|
||||
context['meta_forms'] = self.meta_forms
|
||||
context['item_meta_property_formset'] = self.item_meta_property_formset
|
||||
context['confirm_texts_formset'] = self.confirm_texts_formset
|
||||
context['footer_links_formset'] = self.footer_links_formset
|
||||
return context
|
||||
|
||||
@transaction.atomic
|
||||
@@ -195,6 +196,7 @@ class EventUpdate(DecoupleMixin, EventSettingsViewMixin, EventPermissionRequired
|
||||
self.save_meta()
|
||||
self.save_item_meta_property_formset(self.object)
|
||||
self.save_confirm_texts_formset(self.object)
|
||||
self.save_footer_links_formset(self.object)
|
||||
change_css = False
|
||||
|
||||
if self.sform.has_changed() or self.confirm_texts_formset.has_changed():
|
||||
@@ -204,6 +206,10 @@ class EventUpdate(DecoupleMixin, EventSettingsViewMixin, EventPermissionRequired
|
||||
self.request.event.log_action('pretix.event.settings', user=self.request.user, data=data)
|
||||
if any(p in self.sform.changed_data for p in SETTINGS_AFFECTING_CSS):
|
||||
change_css = True
|
||||
if self.footer_links_formset.has_changed():
|
||||
self.request.event.log_action('pretix.event.footerlinks.changed', user=self.request.user, data={
|
||||
'data': self.footer_links_formset.cleaned_data
|
||||
})
|
||||
if form.has_changed():
|
||||
self.request.event.log_action('pretix.event.changed', user=self.request.user, data={
|
||||
k: (form.cleaned_data.get(k).name
|
||||
@@ -238,7 +244,8 @@ class EventUpdate(DecoupleMixin, EventSettingsViewMixin, EventPermissionRequired
|
||||
def post(self, request, *args, **kwargs):
|
||||
form = self.get_form()
|
||||
if form.is_valid() and self.sform.is_valid() and all([f.is_valid() for f in self.meta_forms]) and \
|
||||
self.item_meta_property_formset.is_valid() and self.confirm_texts_formset.is_valid():
|
||||
self.item_meta_property_formset.is_valid() and self.confirm_texts_formset.is_valid() and \
|
||||
self.footer_links_formset.is_valid():
|
||||
# reset timezone
|
||||
zone = timezone(self.sform.cleaned_data['timezone'])
|
||||
event = form.instance
|
||||
@@ -292,10 +299,18 @@ class EventUpdate(DecoupleMixin, EventSettingsViewMixin, EventPermissionRequired
|
||||
def save_confirm_texts_formset(self, obj):
|
||||
obj.settings.confirm_texts = LazyI18nStringList(
|
||||
form_data['text'].data
|
||||
for form_data in sorted(self.confirm_texts_formset.cleaned_data, key=operator.itemgetter("ORDER"))
|
||||
if not form_data.get("DELETE", False)
|
||||
for form_data in sorted((d for d in self.confirm_texts_formset.cleaned_data if d), key=operator.itemgetter("ORDER"))
|
||||
if form_data and not form_data.get("DELETE", False)
|
||||
)
|
||||
|
||||
@cached_property
|
||||
def footer_links_formset(self):
|
||||
return EventFooterLinkFormset(self.request.POST if self.request.method == "POST" else None, event=self.object,
|
||||
prefix="footer-links", instance=self.object)
|
||||
|
||||
def save_footer_links_formset(self, obj):
|
||||
self.footer_links_formset.save()
|
||||
|
||||
|
||||
class EventPlugins(EventSettingsViewMixin, EventPermissionRequiredMixin, TemplateView, SingleObjectMixin):
|
||||
model = Event
|
||||
|
||||
@@ -92,8 +92,8 @@ from pretix.control.forms.organizer import (
|
||||
CustomerCreateForm, CustomerUpdateForm, DeviceBulkEditForm, DeviceForm,
|
||||
EventMetaPropertyForm, GateForm, GiftCardCreateForm, GiftCardUpdateForm,
|
||||
MailSettingsForm, MembershipTypeForm, MembershipUpdateForm,
|
||||
OrganizerDeleteForm, OrganizerForm, OrganizerSettingsForm,
|
||||
OrganizerUpdateForm, TeamForm, WebHookForm,
|
||||
OrganizerDeleteForm, OrganizerFooterLinkFormset, OrganizerForm,
|
||||
OrganizerSettingsForm, OrganizerUpdateForm, TeamForm, WebHookForm,
|
||||
)
|
||||
from pretix.control.logdisplay import OVERVIEW_BANLIST
|
||||
from pretix.control.permissions import (
|
||||
@@ -416,11 +416,13 @@ class OrganizerUpdate(OrganizerPermissionRequiredMixin, UpdateView):
|
||||
def get_context_data(self, *args, **kwargs) -> dict:
|
||||
context = super().get_context_data(*args, **kwargs)
|
||||
context['sform'] = self.sform
|
||||
context['footer_links_formset'] = self.footer_links_formset
|
||||
return context
|
||||
|
||||
@transaction.atomic
|
||||
def form_valid(self, form):
|
||||
self.sform.save()
|
||||
self.save_footer_links_formset(self.object)
|
||||
change_css = False
|
||||
if self.sform.has_changed():
|
||||
self.request.organizer.log_action(
|
||||
@@ -435,6 +437,10 @@ class OrganizerUpdate(OrganizerPermissionRequiredMixin, UpdateView):
|
||||
)
|
||||
if any(p in self.sform.changed_data for p in SETTINGS_AFFECTING_CSS):
|
||||
change_css = True
|
||||
if self.footer_links_formset.has_changed():
|
||||
self.request.organizer.log_action('pretix.organizer.footerlinks.changed', user=self.request.user, data={
|
||||
'data': self.footer_links_formset.cleaned_data
|
||||
})
|
||||
if form.has_changed():
|
||||
self.request.organizer.log_action(
|
||||
'pretix.organizer.changed',
|
||||
@@ -466,11 +472,19 @@ class OrganizerUpdate(OrganizerPermissionRequiredMixin, UpdateView):
|
||||
def post(self, request, *args, **kwargs):
|
||||
self.object = self.get_object()
|
||||
form = self.get_form()
|
||||
if form.is_valid() and self.sform.is_valid():
|
||||
if form.is_valid() and self.sform.is_valid() and self.footer_links_formset.is_valid():
|
||||
return self.form_valid(form)
|
||||
else:
|
||||
return self.form_invalid(form)
|
||||
|
||||
@cached_property
|
||||
def footer_links_formset(self):
|
||||
return OrganizerFooterLinkFormset(self.request.POST if self.request.method == "POST" else None, organizer=self.object,
|
||||
prefix="footer-links", instance=self.object)
|
||||
|
||||
def save_footer_links_formset(self, obj):
|
||||
self.footer_links_formset.save()
|
||||
|
||||
|
||||
class OrganizerCreate(CreateView):
|
||||
model = Organizer
|
||||
|
||||
@@ -25,7 +25,7 @@ from io import BytesIO
|
||||
|
||||
from django.core.files.base import ContentFile
|
||||
from django.core.files.storage import default_storage
|
||||
from PIL import Image, ImageOps
|
||||
from PIL import Image, ImageOps, ImageSequence
|
||||
from PIL.Image import Resampling
|
||||
|
||||
from pretix.helpers.models import Thumbnail
|
||||
@@ -171,12 +171,23 @@ def create_thumbnail(sourcename, size):
|
||||
except:
|
||||
raise ThumbnailError('Could not load image')
|
||||
|
||||
image = resize_image(image, size)
|
||||
frames = [resize_image(frame, size) for frame in ImageSequence.Iterator(image)]
|
||||
image_out = frames[0]
|
||||
save_kwargs = {}
|
||||
|
||||
if source.name.lower().endswith('.jpg') or source.name.lower().endswith('.jpeg'):
|
||||
# Yields better file sizes for photos
|
||||
target_ext = 'jpeg'
|
||||
quality = 95
|
||||
elif source.name.lower().endswith('.gif') or source.name.lower().endswith('.png'):
|
||||
target_ext = source.name.lower()[-3:]
|
||||
quality = None
|
||||
image_out.info = image.info
|
||||
save_kwargs = {
|
||||
'append_images': frames[1:],
|
||||
'loop': image.info.get('loop', 0),
|
||||
'save_all': True,
|
||||
}
|
||||
else:
|
||||
target_ext = 'png'
|
||||
quality = None
|
||||
@@ -184,11 +195,11 @@ def create_thumbnail(sourcename, size):
|
||||
checksum = hashlib.md5(image.tobytes()).hexdigest()
|
||||
name = checksum + '.' + size.replace('^', 'c') + '.' + target_ext
|
||||
buffer = BytesIO()
|
||||
if image.mode == "P" and source.name.lower().endswith('.png'):
|
||||
image = image.convert('RGBA')
|
||||
if image.mode not in ("1", "L", "RGB", "RGBA"):
|
||||
image = image.convert('RGB')
|
||||
image.save(fp=buffer, format=target_ext.upper(), quality=quality)
|
||||
if image_out.mode == "P" and source.name.lower().endswith('.png'):
|
||||
image_out = image_out.convert('RGBA')
|
||||
if image_out.mode not in ("1", "L", "RGB", "RGBA"):
|
||||
image_out = image_out.convert('RGB')
|
||||
image_out.save(fp=buffer, format=target_ext.upper(), quality=quality, **save_kwargs)
|
||||
imgfile = ContentFile(buffer.getvalue())
|
||||
|
||||
t = Thumbnail.objects.create(source=sourcename, size=size)
|
||||
|
||||
@@ -8,7 +8,7 @@ msgstr ""
|
||||
"Project-Id-Version: PACKAGE VERSION\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2022-06-09 15:47+0000\n"
|
||||
"PO-Revision-Date: 2022-04-27 09:15+0000\n"
|
||||
"PO-Revision-Date: 2022-06-16 09:24+0000\n"
|
||||
"Last-Translator: Raphael Michel <michel@rami.io>\n"
|
||||
"Language-Team: Dutch (informal) <https://translate.pretix.eu/projects/pretix/"
|
||||
"pretix/nl_Informal/>\n"
|
||||
@@ -17,7 +17,7 @@ msgstr ""
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"Plural-Forms: nplurals=2; plural=n != 1;\n"
|
||||
"X-Generator: Weblate 4.11.2\n"
|
||||
"X-Generator: Weblate 4.12.2\n"
|
||||
|
||||
#: pretix/api/auth/devicesecurity.py:28
|
||||
msgid ""
|
||||
@@ -323,10 +323,8 @@ msgid "Event details changed"
|
||||
msgstr "Evenementsdetails aangepast"
|
||||
|
||||
#: pretix/api/webhooks.py:264
|
||||
#, fuzzy
|
||||
#| msgid "Event date"
|
||||
msgid "Event deleted"
|
||||
msgstr "Evenementdatum"
|
||||
msgstr "Evenement verwijderd"
|
||||
|
||||
#: pretix/api/webhooks.py:268
|
||||
msgctxt "subevent"
|
||||
@@ -531,10 +529,8 @@ msgstr ""
|
||||
"dat de factuurdatum niet altijd overeenkomt met de bestel- of betaaldatum."
|
||||
|
||||
#: pretix/base/exporters/events.py:47
|
||||
#, fuzzy
|
||||
#| msgid "Event date"
|
||||
msgid "Event data"
|
||||
msgstr "Evenementdatum"
|
||||
msgstr "Evenement datum"
|
||||
|
||||
#: pretix/base/exporters/events.py:55 pretix/base/exporters/waitinglist.py:112
|
||||
#: pretix/base/models/event.py:459 pretix/base/pdf.py:214
|
||||
@@ -1680,10 +1676,8 @@ msgid "Infinite"
|
||||
msgstr "Oneindig"
|
||||
|
||||
#: pretix/base/exporters/orderlist.py:887
|
||||
#, fuzzy
|
||||
#| msgid "Gift card redemptions"
|
||||
msgid "Gift card transactions"
|
||||
msgstr "Cadeaubonverzilveringen"
|
||||
msgstr "Cadeaubon transactie"
|
||||
|
||||
#: pretix/base/exporters/orderlist.py:931
|
||||
#: pretix/base/exporters/orderlist.py:975
|
||||
@@ -1955,10 +1949,8 @@ msgid "Repeat password"
|
||||
msgstr "Herhaal wachtwoord"
|
||||
|
||||
#: pretix/base/forms/questions.py:198
|
||||
#, fuzzy
|
||||
#| msgid "Please enter a shorter name."
|
||||
msgid "Please do not use special characters in names."
|
||||
msgstr "Vul alsjeblieft een kortere naam in."
|
||||
msgstr "Gebruik alsjeblieft geen speciale karakters in namen."
|
||||
|
||||
#: pretix/base/forms/questions.py:257
|
||||
msgid "Please enter a shorter name."
|
||||
@@ -2030,7 +2022,7 @@ msgstr ""
|
||||
|
||||
#: pretix/base/forms/questions.py:967 pretix/base/forms/questions.py:973
|
||||
msgid "If you are registered in Switzerland, you can enter your UID instead."
|
||||
msgstr ""
|
||||
msgstr "Je kan je UID invullen als je bent geregistreerd in Zwitserland."
|
||||
|
||||
#: pretix/base/forms/questions.py:971
|
||||
msgid ""
|
||||
@@ -2069,7 +2061,7 @@ msgstr "Het huidige wachtwoord dat je hebt ingevoerd is niet correct."
|
||||
|
||||
#: pretix/base/forms/user.py:58
|
||||
msgid "Please choose a password different to your current one."
|
||||
msgstr ""
|
||||
msgstr "Gebruik een wachtwoord dat anders is dan je huidige wachtwoord."
|
||||
|
||||
#: pretix/base/forms/user.py:63 pretix/presale/forms/customer.py:386
|
||||
#: pretix/presale/forms/customer.py:455
|
||||
@@ -2360,10 +2352,8 @@ msgid "Date joined"
|
||||
msgstr "Datum toegevoegd"
|
||||
|
||||
#: pretix/base/models/auth.py:254
|
||||
#, fuzzy
|
||||
#| msgid "Repeat new password"
|
||||
msgid "Force user to select a new password"
|
||||
msgstr "Herhaal nieuw wachtwoord"
|
||||
msgstr "Forceer gebruiker een nieuw wachtwoord in te stellen"
|
||||
|
||||
#: pretix/base/models/auth.py:261
|
||||
msgid "Timezone"
|
||||
@@ -2556,15 +2546,13 @@ msgstr "Registratiedatum"
|
||||
#: pretix/control/templates/pretixcontrol/organizers/customer.html:31
|
||||
#: pretix/control/templates/pretixcontrol/organizers/customers.html:65
|
||||
#: pretix/control/templates/pretixcontrol/users/form.html:43
|
||||
#, fuzzy
|
||||
#| msgid "Internal identifier"
|
||||
msgid "External identifier"
|
||||
msgstr "Intern kenmerk"
|
||||
msgstr "Extern kenmerk"
|
||||
|
||||
#: pretix/base/models/customers.py:75
|
||||
#: pretix/control/templates/pretixcontrol/organizers/customer.html:67
|
||||
msgid "Notes"
|
||||
msgstr ""
|
||||
msgstr "Notities"
|
||||
|
||||
#: pretix/base/models/customers.py:238 pretix/base/models/orders.py:1318
|
||||
#: pretix/base/models/orders.py:2693 pretix/base/settings.py:841
|
||||
@@ -2668,37 +2656,28 @@ msgid "Available until"
|
||||
msgstr "Beschikbaar tot"
|
||||
|
||||
#: pretix/base/models/discount.py:84
|
||||
#, fuzzy
|
||||
#| msgctxt "subevent"
|
||||
#| msgid "Event series date changed"
|
||||
msgid "Event series handling"
|
||||
msgstr "Evenementenreeks: datum aangepast"
|
||||
msgstr "Evenementenreeks verwerking"
|
||||
|
||||
#: pretix/base/models/discount.py:92
|
||||
#, fuzzy
|
||||
#| msgid "All products (including newly created ones)"
|
||||
msgid "Apply to all products (including newly created ones)"
|
||||
msgstr "Alle producten (inclusief nieuw gemaakte)"
|
||||
msgstr "Toepassen op alle producten (inclusief nieuw gemaakte)"
|
||||
|
||||
#: pretix/base/models/discount.py:96
|
||||
#, fuzzy
|
||||
#| msgid "Apply to products"
|
||||
msgid "Apply to specific products"
|
||||
msgstr "Toepassen op producten"
|
||||
msgstr "Toepassen op specifieke producten"
|
||||
|
||||
#: pretix/base/models/discount.py:101
|
||||
#, fuzzy
|
||||
#| msgid "Apply to products"
|
||||
msgid "Apply to add-on products"
|
||||
msgstr "Toepassen op producten"
|
||||
msgstr "Toepassen op add-on producten"
|
||||
|
||||
#: pretix/base/models/discount.py:102
|
||||
msgid "Discounts never apply to bundled products"
|
||||
msgstr ""
|
||||
msgstr "Kortingen worden nooit toegepast op gebundelde producten"
|
||||
|
||||
#: pretix/base/models/discount.py:106
|
||||
msgid "Ignore products discounted by a voucher"
|
||||
msgstr ""
|
||||
msgstr "Negeer producten gevonden door een voucher"
|
||||
|
||||
#: pretix/base/models/discount.py:107
|
||||
msgid ""
|
||||
@@ -2720,11 +2699,11 @@ msgstr ""
|
||||
|
||||
#: pretix/base/models/discount.py:123
|
||||
msgid "Percentual discount on matching products"
|
||||
msgstr ""
|
||||
msgstr "Percentuele korting op gelijke producten"
|
||||
|
||||
#: pretix/base/models/discount.py:130
|
||||
msgid "Apply discount only to this number of matching products"
|
||||
msgstr ""
|
||||
msgstr "Pas korting alleen toe op dit aantal gelijke producten"
|
||||
|
||||
#: pretix/base/models/discount.py:132
|
||||
msgid ""
|
||||
@@ -2827,10 +2806,8 @@ msgid "Event series"
|
||||
msgstr "Evenementenreeks"
|
||||
|
||||
#: pretix/base/models/event.py:535 pretix/base/models/event.py:1341
|
||||
#, fuzzy
|
||||
#| msgid "Settings"
|
||||
msgid "Seating plan"
|
||||
msgstr "Instellingen"
|
||||
msgstr "Stoelverdeling"
|
||||
|
||||
#: pretix/base/models/event.py:542 pretix/base/payment.py:356
|
||||
msgid "Restrict to specific sales channels"
|
||||
@@ -3350,10 +3327,8 @@ msgid "Allowed membership types"
|
||||
msgstr "Toegestane lidmaatschapstypen"
|
||||
|
||||
#: pretix/base/models/items.py:529 pretix/base/models/items.py:824
|
||||
#, fuzzy
|
||||
#| msgid "Has valid membership"
|
||||
msgid "Hide without a valid membership"
|
||||
msgstr "Heeft een geldig lidmaatschap"
|
||||
msgstr "Verberg zonder geldig lidmaatschap"
|
||||
|
||||
#: pretix/base/models/items.py:530 pretix/base/models/items.py:825
|
||||
msgid ""
|
||||
@@ -3424,10 +3399,8 @@ msgid "This is shown below the variation name in lists."
|
||||
msgstr "Dit wordt weergegeven onder de variantnaam in lijsten."
|
||||
|
||||
#: pretix/base/models/items.py:808
|
||||
#, fuzzy
|
||||
#| msgid "New order requires approval"
|
||||
msgid "Require approval"
|
||||
msgstr "Nieuwe bestelling vereist goedkeuring"
|
||||
msgstr "Vereist goedkeuring"
|
||||
|
||||
#: pretix/base/models/items.py:810
|
||||
#, fuzzy
|
||||
@@ -3925,10 +3898,9 @@ msgid "Quota {val}"
|
||||
msgstr "Quotum {val}"
|
||||
|
||||
#: pretix/base/models/log.py:206
|
||||
#, fuzzy, python-brace-format
|
||||
#| msgid "Product {val}"
|
||||
#, python-brace-format
|
||||
msgid "Discount {val}"
|
||||
msgstr "Product {val}"
|
||||
msgstr "Korting {val}"
|
||||
|
||||
#: pretix/base/models/log.py:216
|
||||
#, python-brace-format
|
||||
@@ -4104,10 +4076,9 @@ msgid "The voucher \"{voucher}\" has been used in the meantime."
|
||||
msgstr "De voucher \"{voucher}\" is in de tussentijd gebruikt."
|
||||
|
||||
#: pretix/base/models/orders.py:1023 pretix/control/views/event.py:758
|
||||
#, fuzzy, python-format
|
||||
#| msgid "Your order: {code}"
|
||||
#, python-format
|
||||
msgid "Your order: %(code)s"
|
||||
msgstr "Je bestelling: {code}"
|
||||
msgstr "Je bestelling: %(code)s"
|
||||
|
||||
#: pretix/base/models/orders.py:1187
|
||||
msgid "<file>"
|
||||
@@ -4240,7 +4211,7 @@ msgstr "Annuleringskosten"
|
||||
|
||||
#: pretix/base/models/orders.py:2029
|
||||
msgid "Insurance fee"
|
||||
msgstr ""
|
||||
msgstr "Verzekeringstoeslag"
|
||||
|
||||
#: pretix/base/models/orders.py:2030
|
||||
msgid "Other fees"
|
||||
@@ -4264,10 +4235,9 @@ msgid "Order position"
|
||||
msgstr "Besteld product"
|
||||
|
||||
#: pretix/base/models/orders.py:2405
|
||||
#, fuzzy, python-format
|
||||
#| msgid "Your event registration: {code}"
|
||||
#, python-format
|
||||
msgid "Your event registration: %(code)s"
|
||||
msgstr "Je aanmelding: {code}"
|
||||
msgstr "Je aanmeldingscode: %(code)s"
|
||||
|
||||
#: pretix/base/models/orders.py:2579
|
||||
msgid "Cart ID (e.g. session key)"
|
||||
@@ -4439,7 +4409,7 @@ msgstr "Stoel {number}"
|
||||
|
||||
#: pretix/base/models/tax.py:145
|
||||
msgid "Official name"
|
||||
msgstr ""
|
||||
msgstr "Officiële naam"
|
||||
|
||||
#: pretix/base/models/tax.py:146
|
||||
msgid "Should be short, e.g. \"VAT\""
|
||||
|
||||
@@ -118,6 +118,10 @@ def _default_context(request):
|
||||
_footer += response
|
||||
else:
|
||||
_footer.append(response)
|
||||
_footer += request.event.cache.get_or_set('footer_links', lambda: [
|
||||
{'url': fl.url, 'label': fl.label}
|
||||
for fl in request.event.footer_links.all()
|
||||
], timeout=300)
|
||||
|
||||
if request.event.settings.presale_css_file:
|
||||
ctx['css_file'] = default_storage.url(request.event.settings.presale_css_file)
|
||||
@@ -158,6 +162,10 @@ def _default_context(request):
|
||||
ctx['organizer_logo'] = request.organizer.settings.get('organizer_logo_image', as_type=str, default='')[7:]
|
||||
ctx['organizer_homepage_text'] = request.organizer.settings.get('organizer_homepage_text', as_type=LazyI18nString)
|
||||
ctx['organizer'] = request.organizer
|
||||
_footer += request.organizer.cache.get_or_set('footer_links', lambda: [
|
||||
{'url': fl.url, 'label': fl.label}
|
||||
for fl in request.organizer.footer_links.all()
|
||||
], timeout=300)
|
||||
|
||||
ctx['html_head'] = "".join(h for h in _html_head if h)
|
||||
ctx['html_foot'] = "".join(h for h in _html_foot if h)
|
||||
|
||||
@@ -184,7 +184,7 @@ setup(
|
||||
'django-mysql',
|
||||
'django-oauth-toolkit==1.2.*',
|
||||
'django-otp==1.1.*',
|
||||
'django-phonenumber-field==6.0.*',
|
||||
'django-phonenumber-field==6.3.*',
|
||||
'django-redis==5.0.*',
|
||||
'django-scopes==1.2.*',
|
||||
'django-statici18n==2.2.*',
|
||||
|
||||
@@ -1673,6 +1673,8 @@ def test_order_change_patch(token_client, organizer, event, order, quota):
|
||||
assert p.item == item2
|
||||
f.refresh_from_db()
|
||||
assert f.value == Decimal('10.00')
|
||||
order.refresh_from_db()
|
||||
assert order.total == Decimal('109.44')
|
||||
|
||||
|
||||
@pytest.mark.django_db
|
||||
|
||||
@@ -1388,6 +1388,7 @@ class OrderChangeManagerTests(TestCase):
|
||||
assert self.order.total == Decimal('0.00')
|
||||
assert self.order.status == Order.STATUS_PAID
|
||||
self.order.status = Order.STATUS_PENDING
|
||||
self.order.save()
|
||||
self.ocm.cancel(self.op2)
|
||||
self.ocm.commit()
|
||||
self.order.refresh_from_db()
|
||||
@@ -1746,6 +1747,7 @@ class OrderChangeManagerTests(TestCase):
|
||||
|
||||
ia.vat_id_validated = False
|
||||
ia.save()
|
||||
self.order.refresh_from_db()
|
||||
|
||||
self.ocm = OrderChangeManager(self.order, None)
|
||||
self.ocm.recalculate_taxes()
|
||||
|
||||
Reference in New Issue
Block a user