forked from CGM_Public/pretix_original
Compare commits
12 Commits
new-docs
...
migration-
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
1736efbdc3 | ||
|
|
5cd7959e86 | ||
|
|
b847612e1a | ||
|
|
832f4e4d68 | ||
|
|
0a23aeece4 | ||
|
|
9622bf41a1 | ||
|
|
dd4bac70be | ||
|
|
1187757b56 | ||
|
|
abe5b4ef53 | ||
|
|
b1fb391d08 | ||
|
|
a95c6d94ee | ||
|
|
4809558343 |
@@ -1059,8 +1059,10 @@ class BaseInvoiceAddressForm(forms.ModelForm):
|
||||
|
||||
super().__init__(*args, **kwargs)
|
||||
|
||||
self.fields["company"].widget.attrs["data-display-dependency"] = f'#id_{self.add_prefix("is_business")}_1'
|
||||
self.fields["vat_id"].widget.attrs["data-display-dependency"] = f'#id_{self.add_prefix("is_business")}_1'
|
||||
# If an individual or company address is acceptable, #id_is_business_0 == individual, _1 == company.
|
||||
# However, if only company addresses are acceptable, #id_is_business_0 == company and is the only choice
|
||||
self.fields["company"].widget.attrs["data-display-dependency"] = f'#id_{self.add_prefix("is_business")}_{int(not self.company_required)}'
|
||||
self.fields["vat_id"].widget.attrs["data-display-dependency"] = f'#id_{self.add_prefix("is_business")}_{int(not self.company_required)}'
|
||||
|
||||
if not self.ask_vat_id:
|
||||
del self.fields['vat_id']
|
||||
|
||||
165
src/pretix/base/logentrytype_registry.py
Normal file
165
src/pretix/base/logentrytype_registry.py
Normal file
@@ -0,0 +1,165 @@
|
||||
#
|
||||
# This file is part of pretix (Community Edition).
|
||||
#
|
||||
# Copyright (C) 2014-2020 Raphael Michel and contributors
|
||||
# Copyright (C) 2020-2021 rami.io GmbH and contributors
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General
|
||||
# Public License as published by the Free Software Foundation in version 3 of the License.
|
||||
#
|
||||
# ADDITIONAL TERMS APPLY: Pursuant to Section 7 of the GNU Affero General Public License, additional terms are
|
||||
# applicable granting you additional permissions and placing additional restrictions on your usage of this software.
|
||||
# Please refer to the pretix LICENSE file to obtain the full terms applicable to this work. If you did not receive
|
||||
# this file, see <https://pretix.eu/about/en/license>.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied
|
||||
# warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
|
||||
# details.
|
||||
#
|
||||
# You should have received a copy of the GNU Affero General Public License along with this program. If not, see
|
||||
# <https://www.gnu.org/licenses/>.
|
||||
#
|
||||
from collections import defaultdict
|
||||
from typing import Optional
|
||||
|
||||
from django.urls import reverse
|
||||
from django.utils.html import format_html
|
||||
from django.utils.translation import gettext_lazy as _
|
||||
|
||||
from pretix.base.signals import EventPluginRegistry
|
||||
|
||||
|
||||
def make_link(a_map, wrapper, is_active=True, event=None, plugin_name=None):
|
||||
if a_map:
|
||||
if 'href' not in a_map:
|
||||
a_map['val'] = format_html('<i>{val}</i>', **a_map)
|
||||
elif is_active:
|
||||
a_map['val'] = format_html('<a href="{href}">{val}</a>', **a_map)
|
||||
elif event and plugin_name:
|
||||
a_map['val'] = format_html(
|
||||
'<i>{val}</i> <a href="{plugin_href}">'
|
||||
'<span data-toggle="tooltip" title="{errmes}" class="fa fa-warning fa-fw"></span></a>',
|
||||
**a_map,
|
||||
errmes=_("The relevant plugin is currently not active. To activate it, click here to go to the plugin settings."),
|
||||
plugin_href=reverse('control:event.settings.plugins', kwargs={
|
||||
'organizer': event.organizer.slug,
|
||||
'event': event.slug,
|
||||
}) + '#plugin_' + plugin_name,
|
||||
)
|
||||
else:
|
||||
a_map['val'] = format_html(
|
||||
'<i>{val}</i> <span data-toggle="tooltip" title="{errmes}" class="fa fa-warning fa-fw"></span>',
|
||||
**a_map,
|
||||
errmes=_("The relevant plugin is currently not active."),
|
||||
)
|
||||
return format_html(wrapper, **a_map)
|
||||
|
||||
|
||||
class LogEntryTypeRegistry(EventPluginRegistry):
|
||||
def __init__(self):
|
||||
super().__init__({'action_type': lambda o: getattr(o, 'action_type')})
|
||||
|
||||
def register(self, *objs):
|
||||
for obj in objs:
|
||||
if not isinstance(obj, LogEntryType):
|
||||
raise TypeError('Entries must be derived from LogEntryType')
|
||||
|
||||
if obj.__module__.startswith('pretix.base.'):
|
||||
raise TypeError('Must not register base classes, only derived ones')
|
||||
|
||||
return super().register(*objs)
|
||||
|
||||
def new_from_dict(self, data):
|
||||
"""
|
||||
Register multiple instance of a `LogEntryType` class with different `action_type`
|
||||
and plain text strings, as given by the items of the specified data dictionary.
|
||||
|
||||
This method is designed to be used as a decorator as follows:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
@log_entry_types.new_from_dict({
|
||||
'pretix.event.item.added': _('The product has been created.'),
|
||||
'pretix.event.item.changed': _('The product has been changed.'),
|
||||
# ...
|
||||
})
|
||||
class CoreItemLogEntryType(ItemLogEntryType):
|
||||
# ...
|
||||
|
||||
:param data: action types and descriptions
|
||||
``{"some_action_type": "Plain text description", ...}``
|
||||
"""
|
||||
def reg(clz):
|
||||
for action_type, plain in data.items():
|
||||
self.register(clz(action_type=action_type, plain=plain))
|
||||
return clz
|
||||
return reg
|
||||
|
||||
|
||||
"""
|
||||
Registry for LogEntry types.
|
||||
|
||||
Each entry in this registry should be an instance of a subclass of ``LogEntryType``.
|
||||
They are annotated with their ``action_type`` and the defining ``plugin``.
|
||||
"""
|
||||
log_entry_types = LogEntryTypeRegistry()
|
||||
|
||||
|
||||
class LogEntryType:
|
||||
"""
|
||||
Base class for a type of LogEntry, identified by its action_type.
|
||||
"""
|
||||
|
||||
def __init__(self, action_type=None, plain=None):
|
||||
if action_type:
|
||||
self.action_type = action_type
|
||||
if plain:
|
||||
self.plain = plain
|
||||
|
||||
def display(self, logentry, data):
|
||||
"""
|
||||
Returns the message to be displayed for a given logentry of this type.
|
||||
|
||||
:return: `str` or `LazyI18nString`
|
||||
"""
|
||||
if hasattr(self, 'plain'):
|
||||
plain = str(self.plain)
|
||||
if '{' in plain:
|
||||
data = defaultdict(lambda: '?', data)
|
||||
return plain.format_map(data)
|
||||
else:
|
||||
return plain
|
||||
|
||||
def get_object_link_info(self, logentry) -> Optional[dict]:
|
||||
"""
|
||||
Return information to generate a link to the `content_object` of a given log entry.
|
||||
|
||||
Not implemented in the base class, causing the object link to be omitted.
|
||||
|
||||
:return: Dictionary with the keys ``href`` (URL to view/edit the object) and
|
||||
``val`` (text for the anchor element)
|
||||
"""
|
||||
pass
|
||||
|
||||
def get_object_link(self, logentry):
|
||||
a_map = self.get_object_link_info(logentry)
|
||||
return make_link(a_map, self.object_link_wrapper)
|
||||
|
||||
object_link_wrapper = '{val}'
|
||||
|
||||
def shred_pii(self, logentry):
|
||||
"""
|
||||
To be used for shredding personally identified information contained in the data field of a LogEntry of this
|
||||
type.
|
||||
"""
|
||||
raise NotImplementedError
|
||||
|
||||
|
||||
class NoOpShredderMixin:
|
||||
def shred_pii(self, logentry):
|
||||
pass
|
||||
|
||||
|
||||
class ClearDataShredderMixin:
|
||||
def shred_pii(self, logentry):
|
||||
logentry.data = None
|
||||
@@ -19,137 +19,20 @@
|
||||
# You should have received a copy of the GNU Affero General Public License along with this program. If not, see
|
||||
# <https://www.gnu.org/licenses/>.
|
||||
#
|
||||
from collections import defaultdict
|
||||
from typing import Optional
|
||||
|
||||
from django.urls import reverse
|
||||
from django.utils.html import escape
|
||||
from django.utils.translation import gettext_lazy as _, pgettext_lazy
|
||||
|
||||
from pretix.base.signals import EventPluginRegistry
|
||||
from pretix.base.models import (
|
||||
Discount, Item, ItemCategory, Order, Question, Quota, SubEvent, TaxRule,
|
||||
Voucher,
|
||||
)
|
||||
|
||||
|
||||
def make_link(a_map, wrapper, is_active=True, event=None, plugin_name=None):
|
||||
if a_map:
|
||||
if is_active:
|
||||
a_map['val'] = '<a href="{href}">{val}</a>'.format_map(a_map)
|
||||
elif event and plugin_name:
|
||||
a_map['val'] = (
|
||||
'<i>{val}</i> <a href="{plugin_href}">'
|
||||
'<span data-toggle="tooltip" title="{errmes}" class="fa fa-warning fa-fw"></span></a>'
|
||||
).format_map({
|
||||
**a_map,
|
||||
"errmes": _("The relevant plugin is currently not active. To activate it, click here to go to the plugin settings."),
|
||||
"plugin_href": reverse('control:event.settings.plugins', kwargs={
|
||||
'organizer': event.organizer.slug,
|
||||
'event': event.slug,
|
||||
}) + '#plugin_' + plugin_name,
|
||||
})
|
||||
else:
|
||||
a_map['val'] = '<i>{val}</i> <span data-toggle="tooltip" title="{errmes}" class="fa fa-warning fa-fw"></span>'.format_map({
|
||||
**a_map,
|
||||
"errmes": _("The relevant plugin is currently not active."),
|
||||
})
|
||||
return wrapper.format_map(a_map)
|
||||
|
||||
|
||||
class LogEntryTypeRegistry(EventPluginRegistry):
|
||||
def __init__(self):
|
||||
super().__init__({'action_type': lambda o: getattr(o, 'action_type')})
|
||||
|
||||
def register(self, *objs):
|
||||
for obj in objs:
|
||||
if not isinstance(obj, LogEntryType):
|
||||
raise TypeError('Entries must be derived from LogEntryType')
|
||||
|
||||
if obj.__module__ == LogEntryType.__module__:
|
||||
raise TypeError('Must not register base classes, only derived ones')
|
||||
|
||||
return super().register(*objs)
|
||||
|
||||
def new_from_dict(self, data):
|
||||
"""
|
||||
Register multiple instance of a `LogEntryType` class with different `action_type`
|
||||
and plain text strings, as given by the items of the specified data dictionary.
|
||||
|
||||
This method is designed to be used as a decorator as follows:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
@log_entry_types.new_from_dict({
|
||||
'pretix.event.item.added': _('The product has been created.'),
|
||||
'pretix.event.item.changed': _('The product has been changed.'),
|
||||
# ...
|
||||
})
|
||||
class CoreItemLogEntryType(ItemLogEntryType):
|
||||
# ...
|
||||
|
||||
:param data: action types and descriptions
|
||||
``{"some_action_type": "Plain text description", ...}``
|
||||
"""
|
||||
def reg(clz):
|
||||
for action_type, plain in data.items():
|
||||
self.register(clz(action_type=action_type, plain=plain))
|
||||
return clz
|
||||
return reg
|
||||
|
||||
|
||||
"""
|
||||
Registry for LogEntry types.
|
||||
|
||||
Each entry in this registry should be an instance of a subclass of ``LogEntryType``.
|
||||
They are annotated with their ``action_type`` and the defining ``plugin``.
|
||||
"""
|
||||
log_entry_types = LogEntryTypeRegistry()
|
||||
|
||||
|
||||
class LogEntryType:
|
||||
"""
|
||||
Base class for a type of LogEntry, identified by its action_type.
|
||||
"""
|
||||
|
||||
def __init__(self, action_type=None, plain=None):
|
||||
if action_type:
|
||||
self.action_type = action_type
|
||||
if plain:
|
||||
self.plain = plain
|
||||
|
||||
def display(self, logentry):
|
||||
"""
|
||||
Returns the message to be displayed for a given logentry of this type.
|
||||
|
||||
:return: `str` or `LazyI18nString`
|
||||
"""
|
||||
if hasattr(self, 'plain'):
|
||||
plain = str(self.plain)
|
||||
if '{' in plain:
|
||||
data = defaultdict(lambda: '?', logentry.parsed_data)
|
||||
return plain.format_map(data)
|
||||
else:
|
||||
return plain
|
||||
|
||||
def get_object_link_info(self, logentry) -> dict:
|
||||
"""
|
||||
Return information to generate a link to the `content_object` of a given log entry.
|
||||
|
||||
Not implemented in the base class, causing the object link to be omitted.
|
||||
|
||||
:return: Dictionary with the keys ``href`` (containing a URL to view/edit the object) and ``val`` (containing the
|
||||
escaped text for the anchor element)
|
||||
"""
|
||||
pass
|
||||
|
||||
def get_object_link(self, logentry):
|
||||
a_map = self.get_object_link_info(logentry)
|
||||
return make_link(a_map, self.object_link_wrapper)
|
||||
|
||||
object_link_wrapper = '{val}'
|
||||
|
||||
def shred_pii(self, logentry):
|
||||
"""
|
||||
To be used for shredding personally identified information contained in the data field of a LogEntry of this
|
||||
type.
|
||||
"""
|
||||
raise NotImplementedError
|
||||
from .logentrytype_registry import ( # noqa
|
||||
ClearDataShredderMixin, LogEntryType, NoOpShredderMixin, log_entry_types,
|
||||
make_link, LogEntryTypeRegistry,
|
||||
)
|
||||
|
||||
|
||||
class EventLogEntryType(LogEntryType):
|
||||
@@ -157,15 +40,27 @@ class EventLogEntryType(LogEntryType):
|
||||
Base class for any `LogEntry` type whose `content_object` is either an `Event` itself or belongs to a specific `Event`.
|
||||
"""
|
||||
|
||||
def get_object_link_info(self, logentry) -> dict:
|
||||
if hasattr(self, 'object_link_viewname') and logentry.content_object:
|
||||
def get_object_link_info(self, logentry) -> Optional[dict]:
|
||||
if hasattr(self, 'object_link_viewname'):
|
||||
content = logentry.content_object
|
||||
if not content:
|
||||
if logentry.content_type_id:
|
||||
return {
|
||||
'val': _('(deleted)'),
|
||||
}
|
||||
else:
|
||||
return
|
||||
|
||||
if hasattr(self, 'content_type') and not isinstance(content, self.content_type):
|
||||
return
|
||||
|
||||
return {
|
||||
'href': reverse(self.object_link_viewname, kwargs={
|
||||
'event': logentry.event.slug,
|
||||
'organizer': logentry.event.organizer.slug,
|
||||
**self.object_link_args(logentry.content_object),
|
||||
**self.object_link_args(content),
|
||||
}),
|
||||
'val': escape(self.object_link_display_name(logentry.content_object)),
|
||||
'val': self.object_link_display_name(logentry.content_object),
|
||||
}
|
||||
|
||||
def object_link_args(self, content_object):
|
||||
@@ -182,6 +77,7 @@ class EventLogEntryType(LogEntryType):
|
||||
class OrderLogEntryType(EventLogEntryType):
|
||||
object_link_wrapper = _('Order {val}')
|
||||
object_link_viewname = 'control:event.order'
|
||||
content_type = Order
|
||||
|
||||
def object_link_args(self, order):
|
||||
return {'code': order.code}
|
||||
@@ -194,6 +90,7 @@ class VoucherLogEntryType(EventLogEntryType):
|
||||
object_link_wrapper = _('Voucher {val}…')
|
||||
object_link_viewname = 'control:event.voucher'
|
||||
object_link_argname = 'voucher'
|
||||
content_type = Voucher
|
||||
|
||||
def object_link_display_name(self, voucher):
|
||||
if len(voucher.code) > 6:
|
||||
@@ -205,49 +102,46 @@ class ItemLogEntryType(EventLogEntryType):
|
||||
object_link_wrapper = _('Product {val}')
|
||||
object_link_viewname = 'control:event.item'
|
||||
object_link_argname = 'item'
|
||||
content_type = Item
|
||||
|
||||
|
||||
class SubEventLogEntryType(EventLogEntryType):
|
||||
object_link_wrapper = pgettext_lazy('subevent', 'Date {val}')
|
||||
object_link_viewname = 'control:event.subevent'
|
||||
object_link_argname = 'subevent'
|
||||
content_type = SubEvent
|
||||
|
||||
|
||||
class QuotaLogEntryType(EventLogEntryType):
|
||||
object_link_wrapper = _('Quota {val}')
|
||||
object_link_viewname = 'control:event.items.quotas.show'
|
||||
object_link_argname = 'quota'
|
||||
content_type = Quota
|
||||
|
||||
|
||||
class DiscountLogEntryType(EventLogEntryType):
|
||||
object_link_wrapper = _('Discount {val}')
|
||||
object_link_viewname = 'control:event.items.discounts.edit'
|
||||
object_link_argname = 'discount'
|
||||
content_type = Discount
|
||||
|
||||
|
||||
class ItemCategoryLogEntryType(EventLogEntryType):
|
||||
object_link_wrapper = _('Category {val}')
|
||||
object_link_viewname = 'control:event.items.categories.edit'
|
||||
object_link_argname = 'category'
|
||||
content_type = ItemCategory
|
||||
|
||||
|
||||
class QuestionLogEntryType(EventLogEntryType):
|
||||
object_link_wrapper = _('Question {val}')
|
||||
object_link_viewname = 'control:event.items.questions.show'
|
||||
object_link_argname = 'question'
|
||||
content_type = Question
|
||||
|
||||
|
||||
class TaxRuleLogEntryType(EventLogEntryType):
|
||||
object_link_wrapper = _('Tax rule {val}')
|
||||
object_link_viewname = 'control:event.settings.tax.edit'
|
||||
object_link_argname = 'rule'
|
||||
|
||||
|
||||
class NoOpShredderMixin:
|
||||
def shred_pii(self, logentry):
|
||||
pass
|
||||
|
||||
|
||||
class ClearDataShredderMixin:
|
||||
def shred_pii(self, logentry):
|
||||
logentry.data = None
|
||||
content_type = TaxRule
|
||||
|
||||
@@ -0,0 +1,18 @@
|
||||
# Generated by Django 4.2.16 on 2025-01-23 11:27
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
("pretixbase", "0275_alter_question_valid_number_max_and_more"),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AddField(
|
||||
model_name="item",
|
||||
name="hidden_if_item_available_mode",
|
||||
field=models.CharField(default="hide", max_length=16, null=True),
|
||||
),
|
||||
]
|
||||
@@ -40,7 +40,7 @@ from django.contrib.contenttypes.models import ContentType
|
||||
from django.db import models
|
||||
from django.utils.functional import cached_property
|
||||
|
||||
from pretix.base.logentrytypes import log_entry_types, make_link
|
||||
from pretix.base.logentrytype_registry import log_entry_types, make_link
|
||||
from pretix.base.signals import is_app_active, logentry_object_link
|
||||
|
||||
|
||||
@@ -93,7 +93,7 @@ class LogEntry(models.Model):
|
||||
def display(self):
|
||||
log_entry_type, meta = log_entry_types.get(action_type=self.action_type)
|
||||
if log_entry_type:
|
||||
return log_entry_type.display(self)
|
||||
return log_entry_type.display(self, self.parsed_data)
|
||||
|
||||
from ..signals import logentry_display
|
||||
|
||||
|
||||
@@ -355,7 +355,7 @@ class Order(LockModel, LoggedModel):
|
||||
|
||||
if not self.testmode:
|
||||
raise TypeError("Only test mode orders can be deleted.")
|
||||
self.event.log_action(
|
||||
self.log_action(
|
||||
'pretix.event.order.deleted', user=user, auth=auth,
|
||||
data={
|
||||
'code': self.code,
|
||||
|
||||
@@ -231,7 +231,7 @@ class EventWizardBasicsForm(I18nModelForm):
|
||||
raise ValidationError({
|
||||
'timezone': _('Your default locale must be specified.')
|
||||
})
|
||||
if not data.get("no_taxes") and not data.get("tax_rate"):
|
||||
if not data.get("no_taxes") and data.get("tax_rate") is None:
|
||||
raise ValidationError({
|
||||
'tax_rate': _('You have not specified a tax rate. If you do not want us to compute sales taxes, please '
|
||||
'check "{field}" above.').format(field=self.fields["no_taxes"].label)
|
||||
|
||||
@@ -33,16 +33,16 @@
|
||||
# distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
# License for the specific language governing permissions and limitations under the License.
|
||||
|
||||
import json
|
||||
from collections import defaultdict
|
||||
from decimal import Decimal
|
||||
from typing import Optional
|
||||
|
||||
import bleach
|
||||
import dateutil.parser
|
||||
from django.dispatch import receiver
|
||||
from django.urls import reverse
|
||||
from django.utils.formats import date_format
|
||||
from django.utils.html import escape
|
||||
from django.utils.html import escape, format_html
|
||||
from django.utils.safestring import mark_safe
|
||||
from django.utils.translation import gettext_lazy as _, pgettext_lazy
|
||||
from i18nfield.strings import LazyI18nString
|
||||
@@ -68,128 +68,212 @@ OVERVIEW_BANLIST = [
|
||||
]
|
||||
|
||||
|
||||
def _display_order_changed(event: Event, logentry: LogEntry):
|
||||
data = json.loads(logentry.data)
|
||||
class OrderChangeLogEntryType(OrderLogEntryType):
|
||||
prefix = _('The order has been changed:')
|
||||
|
||||
text = _('The order has been changed:')
|
||||
if logentry.action_type == 'pretix.event.order.changed.item':
|
||||
def display(self, logentry, data):
|
||||
return self.prefix + ' ' + self.display_prefixed(logentry.event, logentry, data)
|
||||
|
||||
def display_prefixed(self, event: Event, logentry: LogEntry, data):
|
||||
return super().display(logentry, data)
|
||||
|
||||
|
||||
class OrderPositionChangeLogEntryType(OrderChangeLogEntryType):
|
||||
prefix = _('The order has been changed:')
|
||||
|
||||
def display(self, logentry, data):
|
||||
return super().display(logentry, {**data, 'posid': data.get('positionid', '?')})
|
||||
|
||||
|
||||
@log_entry_types.new()
|
||||
class OrderItemChanged(OrderChangeLogEntryType):
|
||||
action_type = 'pretix.event.order.changed.item'
|
||||
|
||||
def display_prefixed(self, event: Event, logentry: LogEntry, data):
|
||||
old_item = str(event.items.get(pk=data['old_item']))
|
||||
if data['old_variation']:
|
||||
old_item += ' - ' + str(ItemVariation.objects.get(item__event=event, pk=data['old_variation']))
|
||||
new_item = str(event.items.get(pk=data['new_item']))
|
||||
if data['new_variation']:
|
||||
new_item += ' - ' + str(ItemVariation.objects.get(item__event=event, pk=data['new_variation']))
|
||||
return text + ' ' + _('Position #{posid}: {old_item} ({old_price}) changed '
|
||||
'to {new_item} ({new_price}).').format(
|
||||
return _('Position #{posid}: {old_item} ({old_price}) changed to {new_item} ({new_price}).').format(
|
||||
posid=data.get('positionid', '?'),
|
||||
old_item=old_item, new_item=new_item,
|
||||
old_price=money_filter(Decimal(data['old_price']), event.currency),
|
||||
new_price=money_filter(Decimal(data['new_price']), event.currency),
|
||||
)
|
||||
elif logentry.action_type == 'pretix.event.order.changed.membership':
|
||||
return text + ' ' + _('Position #{posid}: Used membership changed.').format(
|
||||
posid=data.get('positionid', '?'),
|
||||
)
|
||||
elif logentry.action_type == 'pretix.event.order.changed.seat':
|
||||
return text + ' ' + _('Position #{posid}: Seat "{old_seat}" changed '
|
||||
'to "{new_seat}".').format(
|
||||
posid=data.get('positionid', '?'),
|
||||
old_seat=data.get('old_seat'), new_seat=data.get('new_seat'),
|
||||
)
|
||||
elif logentry.action_type == 'pretix.event.order.changed.subevent':
|
||||
|
||||
|
||||
@log_entry_types.new()
|
||||
class OrderMembershipChanged(OrderPositionChangeLogEntryType):
|
||||
action_type = 'pretix.event.order.changed.membership'
|
||||
plain = _('Position #{posid}: Used membership changed.')
|
||||
|
||||
|
||||
@log_entry_types.new()
|
||||
class OrderSeatChanged(OrderPositionChangeLogEntryType):
|
||||
action_type = 'pretix.event.order.changed.seat'
|
||||
plain = _('Position #{posid}: Seat "{old_seat}" changed to "{new_seat}".')
|
||||
|
||||
|
||||
@log_entry_types.new()
|
||||
class OrderSubeventChanged(OrderChangeLogEntryType):
|
||||
action_type = 'pretix.event.order.changed.subevent'
|
||||
|
||||
def display_prefixed(self, event: Event, logentry: LogEntry, data):
|
||||
old_se = str(event.subevents.get(pk=data['old_subevent']))
|
||||
new_se = str(event.subevents.get(pk=data['new_subevent']))
|
||||
return text + ' ' + _('Position #{posid}: Event date "{old_event}" ({old_price}) changed '
|
||||
'to "{new_event}" ({new_price}).').format(
|
||||
return _('Position #{posid}: Event date "{old_event}" ({old_price}) changed '
|
||||
'to "{new_event}" ({new_price}).').format(
|
||||
posid=data.get('positionid', '?'),
|
||||
old_event=old_se, new_event=new_se,
|
||||
old_price=money_filter(Decimal(data['old_price']), event.currency),
|
||||
new_price=money_filter(Decimal(data['new_price']), event.currency),
|
||||
)
|
||||
elif logentry.action_type == 'pretix.event.order.changed.price':
|
||||
return text + ' ' + _('Price of position #{posid} changed from {old_price} '
|
||||
'to {new_price}.').format(
|
||||
|
||||
|
||||
@log_entry_types.new()
|
||||
class OrderPriceChanged(OrderChangeLogEntryType):
|
||||
action_type = 'pretix.event.order.changed.price'
|
||||
|
||||
def display_prefixed(self, event: Event, logentry: LogEntry, data):
|
||||
return _('Price of position #{posid} changed from {old_price} to {new_price}.').format(
|
||||
posid=data.get('positionid', '?'),
|
||||
old_price=money_filter(Decimal(data['old_price']), event.currency),
|
||||
new_price=money_filter(Decimal(data['new_price']), event.currency),
|
||||
)
|
||||
elif logentry.action_type == 'pretix.event.order.changed.tax_rule':
|
||||
|
||||
|
||||
@log_entry_types.new()
|
||||
class OrderTaxRuleChanged(OrderChangeLogEntryType):
|
||||
action_type = 'pretix.event.order.changed.tax_rule'
|
||||
|
||||
def display_prefixed(self, event: Event, logentry: LogEntry, data):
|
||||
if 'positionid' in data:
|
||||
return text + ' ' + _('Tax rule of position #{posid} changed from {old_rule} '
|
||||
'to {new_rule}.').format(
|
||||
return _('Tax rule of position #{posid} changed from {old_rule} to {new_rule}.').format(
|
||||
posid=data.get('positionid', '?'),
|
||||
old_rule=TaxRule.objects.get(pk=data['old_taxrule']) if data['old_taxrule'] else '–',
|
||||
new_rule=TaxRule.objects.get(pk=data['new_taxrule']),
|
||||
)
|
||||
elif 'fee' in data:
|
||||
return text + ' ' + _('Tax rule of fee #{fee} changed from {old_rule} '
|
||||
'to {new_rule}.').format(
|
||||
return _('Tax rule of fee #{fee} changed from {old_rule} to {new_rule}.').format(
|
||||
fee=data.get('fee', '?'),
|
||||
old_rule=TaxRule.objects.get(pk=data['old_taxrule']) if data['old_taxrule'] else '–',
|
||||
new_rule=TaxRule.objects.get(pk=data['new_taxrule']),
|
||||
)
|
||||
elif logentry.action_type == 'pretix.event.order.changed.addfee':
|
||||
return text + ' ' + str(_('A fee has been added'))
|
||||
elif logentry.action_type == 'pretix.event.order.changed.feevalue':
|
||||
return text + ' ' + _('A fee was changed from {old_price} to {new_price}.').format(
|
||||
|
||||
|
||||
@log_entry_types.new()
|
||||
class OrderFeeAdded(OrderChangeLogEntryType):
|
||||
action_type = 'pretix.event.order.changed.addfee'
|
||||
plain = _('A fee has been added')
|
||||
|
||||
|
||||
@log_entry_types.new()
|
||||
class OrderFeeChanged(OrderChangeLogEntryType):
|
||||
action_type = 'pretix.event.order.changed.feevalue'
|
||||
|
||||
def display_prefixed(self, event: Event, logentry: LogEntry, data):
|
||||
return _('A fee was changed from {old_price} to {new_price}.').format(
|
||||
old_price=money_filter(Decimal(data['old_price']), event.currency),
|
||||
new_price=money_filter(Decimal(data['new_price']), event.currency),
|
||||
)
|
||||
elif logentry.action_type == 'pretix.event.order.changed.cancelfee':
|
||||
return text + ' ' + _('A fee of {old_price} was removed.').format(
|
||||
|
||||
|
||||
@log_entry_types.new()
|
||||
class OrderFeeRemoved(OrderChangeLogEntryType):
|
||||
action_type = 'pretix.event.order.changed.cancelfee'
|
||||
|
||||
def display_prefixed(self, event: Event, logentry: LogEntry, data):
|
||||
return _('A fee of {old_price} was removed.').format(
|
||||
old_price=money_filter(Decimal(data['old_price']), event.currency),
|
||||
)
|
||||
elif logentry.action_type == 'pretix.event.order.changed.cancel':
|
||||
|
||||
|
||||
@log_entry_types.new()
|
||||
class OrderCanceled(OrderChangeLogEntryType):
|
||||
action_type = 'pretix.event.order.changed.cancel'
|
||||
|
||||
def display_prefixed(self, event: Event, logentry: LogEntry, data):
|
||||
old_item = str(event.items.get(pk=data['old_item']))
|
||||
if data['old_variation']:
|
||||
old_item += ' - ' + str(ItemVariation.objects.get(pk=data['old_variation']))
|
||||
return text + ' ' + _('Position #{posid} ({old_item}, {old_price}) canceled.').format(
|
||||
return _('Position #{posid} ({old_item}, {old_price}) canceled.').format(
|
||||
posid=data.get('positionid', '?'),
|
||||
old_item=old_item,
|
||||
old_price=money_filter(Decimal(data['old_price']), event.currency),
|
||||
)
|
||||
elif logentry.action_type == 'pretix.event.order.changed.add':
|
||||
|
||||
|
||||
@log_entry_types.new()
|
||||
class OrderPositionAdded(OrderChangeLogEntryType):
|
||||
action_type = 'pretix.event.order.changed.add'
|
||||
|
||||
def display_prefixed(self, event: Event, logentry: LogEntry, data):
|
||||
item = str(event.items.get(pk=data['item']))
|
||||
if data['variation']:
|
||||
item += ' - ' + str(ItemVariation.objects.get(item__event=event, pk=data['variation']))
|
||||
if data['addon_to']:
|
||||
addon_to = OrderPosition.objects.get(order__event=event, pk=data['addon_to'])
|
||||
return text + ' ' + _('Position #{posid} created: {item} ({price}) as an add-on to '
|
||||
'position #{addon_to}.').format(
|
||||
return _('Position #{posid} created: {item} ({price}) as an add-on to position #{addon_to}.').format(
|
||||
posid=data.get('positionid', '?'),
|
||||
item=item, addon_to=addon_to.positionid,
|
||||
price=money_filter(Decimal(data['price']), event.currency),
|
||||
)
|
||||
else:
|
||||
return text + ' ' + _('Position #{posid} created: {item} ({price}).').format(
|
||||
return _('Position #{posid} created: {item} ({price}).').format(
|
||||
posid=data.get('positionid', '?'),
|
||||
item=item,
|
||||
price=money_filter(Decimal(data['price']), event.currency),
|
||||
)
|
||||
elif logentry.action_type == 'pretix.event.order.changed.secret':
|
||||
return text + ' ' + _('A new secret has been generated for position #{posid}.').format(
|
||||
posid=data.get('positionid', '?'),
|
||||
)
|
||||
elif logentry.action_type == 'pretix.event.order.changed.valid_from':
|
||||
return text + ' ' + _('The validity start date for position #{posid} has been changed to {value}.').format(
|
||||
|
||||
|
||||
@log_entry_types.new()
|
||||
class OrderSecretChanged(OrderPositionChangeLogEntryType):
|
||||
action_type = 'pretix.event.order.changed.secret'
|
||||
plain = _('A new secret has been generated for position #{posid}.')
|
||||
|
||||
|
||||
@log_entry_types.new()
|
||||
class OrderValidFromChanged(OrderChangeLogEntryType):
|
||||
action_type = 'pretix.event.order.changed.valid_from'
|
||||
|
||||
def display_prefixed(self, event: Event, logentry: LogEntry, data):
|
||||
return _('The validity start date for position #{posid} has been changed to {value}.').format(
|
||||
posid=data.get('positionid', '?'),
|
||||
value=date_format(dateutil.parser.parse(data.get('new_value')), 'SHORT_DATETIME_FORMAT') if data.get(
|
||||
'new_value') else '–'
|
||||
)
|
||||
elif logentry.action_type == 'pretix.event.order.changed.valid_until':
|
||||
return text + ' ' + _('The validity end date for position #{posid} has been changed to {value}.').format(
|
||||
|
||||
|
||||
@log_entry_types.new()
|
||||
class OrderValidUntilChanged(OrderChangeLogEntryType):
|
||||
action_type = 'pretix.event.order.changed.valid_until'
|
||||
|
||||
def display_prefixed(self, event: Event, logentry: LogEntry, data):
|
||||
return _('The validity end date for position #{posid} has been changed to {value}.').format(
|
||||
posid=data.get('positionid', '?'),
|
||||
value=date_format(dateutil.parser.parse(data.get('new_value')), 'SHORT_DATETIME_FORMAT') if data.get('new_value') else '–'
|
||||
)
|
||||
elif logentry.action_type == 'pretix.event.order.changed.add_block':
|
||||
return text + ' ' + _('A block has been added for position #{posid}.').format(
|
||||
posid=data.get('positionid', '?'),
|
||||
)
|
||||
elif logentry.action_type == 'pretix.event.order.changed.remove_block':
|
||||
return text + ' ' + _('A block has been removed for position #{posid}.').format(
|
||||
posid=data.get('positionid', '?'),
|
||||
)
|
||||
elif logentry.action_type == 'pretix.event.order.changed.split':
|
||||
|
||||
|
||||
@log_entry_types.new()
|
||||
class OrderChangedBlockAdded(OrderPositionChangeLogEntryType):
|
||||
action_type = 'pretix.event.order.changed.add_block'
|
||||
plain = _('A block has been added for position #{posid}.')
|
||||
|
||||
|
||||
@log_entry_types.new()
|
||||
class OrderChangedBlockRemoved(OrderPositionChangeLogEntryType):
|
||||
action_type = 'pretix.event.order.changed.remove_block'
|
||||
plain = _('A block has been removed for position #{posid}.')
|
||||
|
||||
|
||||
@log_entry_types.new()
|
||||
class OrderChangedSplit(OrderChangeLogEntryType):
|
||||
action_type = 'pretix.event.order.changed.split'
|
||||
|
||||
def display_prefixed(self, event: Event, logentry: LogEntry, data):
|
||||
old_item = str(event.items.get(pk=data['old_item']))
|
||||
if data['old_variation']:
|
||||
old_item += ' - ' + str(ItemVariation.objects.get(pk=data['old_variation']))
|
||||
@@ -198,194 +282,144 @@ def _display_order_changed(event: Event, logentry: LogEntry):
|
||||
'organizer': event.organizer.slug,
|
||||
'code': data['new_order']
|
||||
})
|
||||
return mark_safe(escape(text) + ' ' + _('Position #{posid} ({old_item}, {old_price}) split into new order: {order}').format(
|
||||
return mark_safe(self.prefix + ' ' + _('Position #{posid} ({old_item}, {old_price}) split into new order: {order}').format(
|
||||
old_item=escape(old_item),
|
||||
posid=data.get('positionid', '?'),
|
||||
order='<a href="{}">{}</a>'.format(url, data['new_order']),
|
||||
old_price=money_filter(Decimal(data['old_price']), event.currency),
|
||||
))
|
||||
elif logentry.action_type == 'pretix.event.order.changed.split_from':
|
||||
|
||||
|
||||
@log_entry_types.new()
|
||||
class OrderChangedSplitFrom(OrderLogEntryType):
|
||||
action_type = 'pretix.event.order.changed.split_from'
|
||||
|
||||
def display(self, logentry: LogEntry, data):
|
||||
return _('This order has been created by splitting the order {order}').format(
|
||||
order=data['original_order'],
|
||||
)
|
||||
|
||||
|
||||
def _display_checkin(event, logentry):
|
||||
data = logentry.parsed_data
|
||||
@log_entry_types.new_from_dict({
|
||||
'pretix.event.checkin.unknown': (
|
||||
_('Unknown scan of code "{barcode}…" at {datetime} for list "{list}", type "{type}".'),
|
||||
_('Unknown scan of code "{barcode}…" for list "{list}", type "{type}".'),
|
||||
),
|
||||
'pretix.event.checkin.revoked': (
|
||||
_('Scan of revoked code "{barcode}…" at {datetime} for list "{list}", type "{type}", was uploaded.'),
|
||||
_('Scan of revoked code "{barcode}" for list "{list}", type "{type}", was uploaded.'),
|
||||
),
|
||||
'pretix.event.checkin.denied': (
|
||||
_('Denied scan of position #{posid} at {datetime} for list "{list}", type "{type}", error code "{errorcode}".'),
|
||||
_('Denied scan of position #{posid} for list "{list}", type "{type}", error code "{errorcode}".'),
|
||||
),
|
||||
'pretix.control.views.checkin.reverted': _('The check-in of position #{posid} on list "{list}" has been reverted.'),
|
||||
'pretix.event.checkin.reverted': _('The check-in of position #{posid} on list "{list}" has been reverted.'),
|
||||
})
|
||||
class CheckinErrorLogEntryType(OrderLogEntryType):
|
||||
def display(self, logentry: LogEntry, data):
|
||||
self.display_plain(self.plain, logentry, data)
|
||||
|
||||
show_dt = False
|
||||
if 'datetime' in data:
|
||||
dt = dateutil.parser.parse(data.get('datetime'))
|
||||
show_dt = abs((logentry.datetime - dt).total_seconds()) > 5 or 'forced' in data
|
||||
tz = event.timezone
|
||||
dt_formatted = date_format(dt.astimezone(tz), "SHORT_DATETIME_FORMAT")
|
||||
def display_plain(self, plain, logentry: LogEntry, data):
|
||||
if isinstance(plain, tuple):
|
||||
plain_with_dt, plain_without_dt = plain
|
||||
else:
|
||||
plain_with_dt, plain_without_dt = plain, plain
|
||||
|
||||
if 'list' in data:
|
||||
try:
|
||||
checkin_list = event.checkin_lists.get(pk=data.get('list')).name
|
||||
except CheckinList.DoesNotExist:
|
||||
checkin_list = _("(unknown)")
|
||||
else:
|
||||
checkin_list = _("(unknown)")
|
||||
data = defaultdict(lambda: '?', data)
|
||||
|
||||
if logentry.action_type == 'pretix.event.checkin.unknown':
|
||||
if show_dt:
|
||||
return _(
|
||||
'Unknown scan of code "{barcode}…" at {datetime} for list "{list}", type "{type}".'
|
||||
).format(
|
||||
posid=data.get('positionid'),
|
||||
type=data.get('type'),
|
||||
barcode=data.get('barcode')[:16],
|
||||
datetime=dt_formatted,
|
||||
list=checkin_list
|
||||
event = logentry.event
|
||||
|
||||
if 'list' in data:
|
||||
try:
|
||||
data['list'] = event.checkin_lists.get(pk=data.get('list')).name
|
||||
except CheckinList.DoesNotExist:
|
||||
data['list'] = _("(unknown)")
|
||||
else:
|
||||
data['list'] = _("(unknown)")
|
||||
|
||||
data['barcode'] = data.get('barcode')[:16]
|
||||
data['posid'] = logentry.parsed_data.get('positionid', '?')
|
||||
|
||||
if 'datetime' in data:
|
||||
dt = dateutil.parser.parse(data.get('datetime'))
|
||||
if abs((logentry.datetime - dt).total_seconds()) > 5 or 'forced' in data:
|
||||
tz = event.timezone
|
||||
data['datetime'] = date_format(dt.astimezone(tz), "SHORT_DATETIME_FORMAT")
|
||||
return str(plain_with_dt).format_map(data)
|
||||
else:
|
||||
return str(plain_without_dt).format_map(data)
|
||||
|
||||
|
||||
class CheckinLogEntryType(CheckinErrorLogEntryType):
|
||||
def display(self, logentry: LogEntry, data):
|
||||
if data.get('type') == Checkin.TYPE_EXIT:
|
||||
return self.display_plain((
|
||||
_('Position #{posid} has been checked out at {datetime} for list "{list}".'),
|
||||
_('Position #{posid} has been checked out for list "{list}".'),
|
||||
), logentry, data)
|
||||
elif data.get('first'):
|
||||
return self.display_plain((
|
||||
_('Position #{posid} has been checked in at {datetime} for list "{list}".'),
|
||||
_('Position #{posid} has been checked in for list "{list}".'),
|
||||
), logentry, data)
|
||||
elif data.get('forced'):
|
||||
return self.display_plain(
|
||||
_('A scan for position #{posid} at {datetime} for list "{list}" has been uploaded even though it has '
|
||||
'been scanned already.'),
|
||||
logentry, data
|
||||
)
|
||||
else:
|
||||
return _(
|
||||
'Unknown scan of code "{barcode}…" for list "{list}", type "{type}".'
|
||||
).format(
|
||||
posid=data.get('positionid'),
|
||||
type=data.get('type'),
|
||||
barcode=data.get('barcode')[:16],
|
||||
list=checkin_list
|
||||
return self.display_plain(
|
||||
_('Position #{posid} has been scanned and rejected because it has already been scanned before '
|
||||
'on list "{list}".'),
|
||||
logentry, data
|
||||
)
|
||||
|
||||
if logentry.action_type == 'pretix.event.checkin.revoked':
|
||||
if show_dt:
|
||||
return _(
|
||||
'Scan scan of revoked code "{barcode}…" at {datetime} for list "{list}", type "{type}", was uploaded.'
|
||||
).format(
|
||||
posid=data.get('positionid'),
|
||||
type=data.get('type'),
|
||||
barcode=data.get('barcode')[:16],
|
||||
datetime=dt_formatted,
|
||||
list=checkin_list
|
||||
)
|
||||
else:
|
||||
return _(
|
||||
'Scan of revoked code "{barcode}" for list "{list}", type "{type}", was uploaded.'
|
||||
).format(
|
||||
posid=data.get('positionid'),
|
||||
type=data.get('type'),
|
||||
barcode=data.get('barcode')[:16],
|
||||
list=checkin_list
|
||||
)
|
||||
|
||||
if logentry.action_type == 'pretix.event.checkin.denied':
|
||||
if show_dt:
|
||||
return _(
|
||||
'Denied scan of position #{posid} at {datetime} for list "{list}", type "{type}", '
|
||||
'error code "{errorcode}".'
|
||||
).format(
|
||||
posid=data.get('positionid'),
|
||||
type=data.get('type'),
|
||||
errorcode=data.get('errorcode'),
|
||||
datetime=dt_formatted,
|
||||
list=checkin_list
|
||||
)
|
||||
else:
|
||||
return _(
|
||||
'Denied scan of position #{posid} for list "{list}", type "{type}", error code "{errorcode}".'
|
||||
).format(
|
||||
posid=data.get('positionid'),
|
||||
type=data.get('type'),
|
||||
errorcode=data.get('errorcode'),
|
||||
list=checkin_list
|
||||
)
|
||||
class OrderConsentLogEntryType(OrderLogEntryType):
|
||||
action_type = 'pretix.event.order.consent'
|
||||
|
||||
if data.get('type') == Checkin.TYPE_EXIT:
|
||||
if show_dt:
|
||||
return _('Position #{posid} has been checked out at {datetime} for list "{list}".').format(
|
||||
posid=data.get('positionid'),
|
||||
datetime=dt_formatted,
|
||||
list=checkin_list
|
||||
)
|
||||
def display(self, logentry: LogEntry, data):
|
||||
return _('The user confirmed the following message: "{}"').format(
|
||||
bleach.clean(data.get('msg'), tags=set(), strip=True)
|
||||
)
|
||||
|
||||
|
||||
class OrderCanceledLogEntryType(OrderLogEntryType):
|
||||
action_type = 'pretix.event.order.canceled'
|
||||
|
||||
def display(self, logentry: LogEntry, data):
|
||||
comment = data.get('comment')
|
||||
if comment:
|
||||
return _('The order has been canceled (comment: "{comment}").').format(comment=comment)
|
||||
else:
|
||||
return _('Position #{posid} has been checked out for list "{list}".').format(
|
||||
posid=data.get('positionid'),
|
||||
list=checkin_list
|
||||
)
|
||||
if data.get('first'):
|
||||
if show_dt:
|
||||
return _('Position #{posid} has been checked in at {datetime} for list "{list}".').format(
|
||||
posid=data.get('positionid'),
|
||||
datetime=dt_formatted,
|
||||
list=checkin_list
|
||||
)
|
||||
else:
|
||||
return _('Position #{posid} has been checked in for list "{list}".').format(
|
||||
posid=data.get('positionid'),
|
||||
list=checkin_list
|
||||
)
|
||||
else:
|
||||
if data.get('forced'):
|
||||
return _(
|
||||
'A scan for position #{posid} at {datetime} for list "{list}" has been uploaded even though it has '
|
||||
'been scanned already.'.format(
|
||||
posid=data.get('positionid'),
|
||||
datetime=dt_formatted,
|
||||
list=checkin_list
|
||||
)
|
||||
)
|
||||
return _(
|
||||
'Position #{posid} has been scanned and rejected because it has already been scanned before '
|
||||
'on list "{list}".'.format(
|
||||
posid=data.get('positionid'),
|
||||
list=checkin_list
|
||||
)
|
||||
return _('The order has been canceled.')
|
||||
|
||||
|
||||
class OrderPrintLogEntryType(OrderLogEntryType):
|
||||
action_type = 'pretix.event.order.print'
|
||||
|
||||
def display(self, logentry: LogEntry, data):
|
||||
return _('Position #{posid} has been printed at {datetime} with type "{type}".').format(
|
||||
posid=data.get('positionid'),
|
||||
datetime=date_format(
|
||||
dateutil.parser.parse(data["datetime"]).astimezone(logentry.event.timezone),
|
||||
"SHORT_DATETIME_FORMAT"
|
||||
),
|
||||
type=dict(PrintLog.PRINT_TYPES)[data["type"]],
|
||||
)
|
||||
|
||||
|
||||
@receiver(signal=logentry_display, dispatch_uid="pretixcontrol_logentry_display")
|
||||
def pretixcontrol_logentry_display(sender: Event, logentry: LogEntry, **kwargs):
|
||||
|
||||
if logentry.action_type.startswith('pretix.event.order.changed'):
|
||||
return _display_order_changed(sender, logentry)
|
||||
|
||||
if logentry.action_type.startswith('pretix.event.payment.provider.'):
|
||||
return _('The settings of a payment provider have been changed.')
|
||||
|
||||
if logentry.action_type.startswith('pretix.event.tickets.provider.'):
|
||||
return _('The settings of a ticket output provider have been changed.')
|
||||
|
||||
if logentry.action_type == 'pretix.event.order.consent':
|
||||
return _('The user confirmed the following message: "{}"').format(
|
||||
bleach.clean(logentry.parsed_data.get('msg'), tags=set(), strip=True)
|
||||
)
|
||||
|
||||
if logentry.action_type == 'pretix.event.order.canceled':
|
||||
comment = logentry.parsed_data.get('comment')
|
||||
if comment:
|
||||
return _('The order has been canceled (comment: "{comment}").').format(comment=comment)
|
||||
else:
|
||||
return _('The order has been canceled.')
|
||||
|
||||
if logentry.action_type in ('pretix.control.views.checkin.reverted', 'pretix.event.checkin.reverted'):
|
||||
if 'list' in logentry.parsed_data:
|
||||
try:
|
||||
checkin_list = sender.checkin_lists.get(pk=logentry.parsed_data.get('list')).name
|
||||
except CheckinList.DoesNotExist:
|
||||
checkin_list = _("(unknown)")
|
||||
else:
|
||||
checkin_list = _("(unknown)")
|
||||
|
||||
return _('The check-in of position #{posid} on list "{list}" has been reverted.').format(
|
||||
posid=logentry.parsed_data.get('positionid'),
|
||||
list=checkin_list,
|
||||
)
|
||||
|
||||
if sender and logentry.action_type.startswith('pretix.event.checkin'):
|
||||
return _display_checkin(sender, logentry)
|
||||
|
||||
if logentry.action_type == 'pretix.event.order.print':
|
||||
return _('Position #{posid} has been printed at {datetime} with type "{type}".').format(
|
||||
posid=logentry.parsed_data.get('positionid'),
|
||||
datetime=date_format(
|
||||
dateutil.parser.parse(logentry.parsed_data["datetime"]).astimezone(sender.timezone),
|
||||
"SHORT_DATETIME_FORMAT"
|
||||
),
|
||||
type=dict(PrintLog.PRINT_TYPES)[logentry.parsed_data["type"]],
|
||||
)
|
||||
|
||||
|
||||
@receiver(signal=orderposition_blocked_display, dispatch_uid="pretixcontrol_orderposition_blocked_display")
|
||||
def pretixcontrol_orderposition_blocked_display(sender: Event, orderposition, block_name, **kwargs):
|
||||
@@ -396,6 +430,7 @@ def pretixcontrol_orderposition_blocked_display(sender: Event, orderposition, bl
|
||||
|
||||
|
||||
@log_entry_types.new_from_dict({
|
||||
'pretix.event.order.deleted': _('The test mode order {code} has been deleted.'),
|
||||
'pretix.event.order.modified': _('The order details have been changed.'),
|
||||
'pretix.event.order.unpaid': _('The order has been marked as unpaid.'),
|
||||
'pretix.event.order.secret.changed': _('The order\'s secret has been changed.'),
|
||||
@@ -486,17 +521,16 @@ class VoucherRedeemedLogEntryType(VoucherLogEntryType):
|
||||
action_type = 'pretix.voucher.redeemed'
|
||||
plain = _('The voucher has been redeemed in order {order_code}.')
|
||||
|
||||
def display(self, logentry):
|
||||
data = json.loads(logentry.data)
|
||||
data = defaultdict(lambda: '?', data)
|
||||
def display(self, logentry, data):
|
||||
url = reverse('control:event.order', kwargs={
|
||||
'event': logentry.event.slug,
|
||||
'organizer': logentry.event.organizer.slug,
|
||||
'code': data['order_code']
|
||||
'code': data.get('order_code', '?')
|
||||
})
|
||||
return mark_safe(self.plain.format(
|
||||
order_code='<a href="{}">{}</a>'.format(url, data['order_code']),
|
||||
))
|
||||
return format_html(
|
||||
self.plain,
|
||||
order_code=format_html('<a href="{}">{}</a>', url, data('order_code', '?')),
|
||||
)
|
||||
|
||||
|
||||
@log_entry_types.new_from_dict({
|
||||
@@ -519,8 +553,8 @@ class CoreTaxRuleLogEntryType(TaxRuleLogEntryType):
|
||||
|
||||
|
||||
class TeamMembershipLogEntryType(LogEntryType):
|
||||
def display(self, logentry):
|
||||
return self.plain.format(user=logentry.parsed_data.get('email'))
|
||||
def display(self, logentry, data):
|
||||
return self.plain.format(user=data.get('email'))
|
||||
|
||||
|
||||
@log_entry_types.new_from_dict({
|
||||
@@ -537,9 +571,9 @@ class CoreTeamMembershipLogEntryType(TeamMembershipLogEntryType):
|
||||
class TeamMemberJoinedLogEntryType(LogEntryType):
|
||||
action_type = 'pretix.team.member.joined'
|
||||
|
||||
def display(self, logentry):
|
||||
def display(self, logentry, data):
|
||||
return _('{user} has joined the team using the invite sent to {email}.').format(
|
||||
user=logentry.parsed_data.get('email'), email=logentry.parsed_data.get('invite_email')
|
||||
user=data.get('email'), email=data.get('invite_email')
|
||||
)
|
||||
|
||||
|
||||
@@ -547,23 +581,23 @@ class TeamMemberJoinedLogEntryType(LogEntryType):
|
||||
class UserSettingsChangedLogEntryType(LogEntryType):
|
||||
action_type = 'pretix.user.settings.changed'
|
||||
|
||||
def display(self, logentry):
|
||||
def display(self, logentry, data):
|
||||
text = str(_('Your account settings have been changed.'))
|
||||
if 'email' in logentry.parsed_data:
|
||||
if 'email' in data:
|
||||
text = text + ' ' + str(
|
||||
_('Your email address has been changed to {email}.').format(email=logentry.parsed_data['email']))
|
||||
if 'new_pw' in logentry.parsed_data:
|
||||
_('Your email address has been changed to {email}.').format(email=data['email']))
|
||||
if 'new_pw' in data:
|
||||
text = text + ' ' + str(_('Your password has been changed.'))
|
||||
if logentry.parsed_data.get('is_active') is True:
|
||||
if data.get('is_active') is True:
|
||||
text = text + ' ' + str(_('Your account has been enabled.'))
|
||||
elif logentry.parsed_data.get('is_active') is False:
|
||||
elif data.get('is_active') is False:
|
||||
text = text + ' ' + str(_('Your account has been disabled.'))
|
||||
return text
|
||||
|
||||
|
||||
class UserImpersonatedLogEntryType(LogEntryType):
|
||||
def display(self, logentry):
|
||||
return self.plain.format(logentry.parsed_data['other_email'])
|
||||
def display(self, logentry, data):
|
||||
return self.plain.format(data['other_email'])
|
||||
|
||||
|
||||
@log_entry_types.new_from_dict({
|
||||
@@ -688,16 +722,13 @@ class CoreLogEntryType(LogEntryType):
|
||||
|
||||
|
||||
@log_entry_types.new_from_dict({
|
||||
'pretix.event.order.deleted': _('The test mode order {code} has been deleted.'),
|
||||
'pretix.event.item_meta_property.added': _('A meta property has been added to this event.'),
|
||||
'pretix.event.item_meta_property.deleted': _('A meta property has been removed from this event.'),
|
||||
'pretix.event.item_meta_property.changed': _('A meta property has been changed on this event.'),
|
||||
'pretix.event.checkinlist.added': _('The check-in list has been added.'),
|
||||
'pretix.event.checkinlist.deleted': _('The check-in list has been deleted.'),
|
||||
'pretix.event.checkinlists.deleted': _('The check-in list has been deleted.'), # backwards compatibility
|
||||
'pretix.event.checkinlist.changed': _('The check-in list has been changed.'),
|
||||
'pretix.event.settings': _('The event settings have been changed.'),
|
||||
'pretix.event.tickets.settings': _('The ticket download settings have been changed.'),
|
||||
'pretix.event.tickets.provider': _('The settings of a ticket output provider have been changed.'),
|
||||
'pretix.event.payment.provider': _('The settings of a payment provider have been changed.'),
|
||||
'pretix.event.live.activated': _('The shop has been taken live.'),
|
||||
'pretix.event.live.deactivated': _('The shop has been taken offline.'),
|
||||
'pretix.event.testmode.activated': _('The shop has been taken into test mode.'),
|
||||
@@ -717,6 +748,19 @@ class CoreEventLogEntryType(EventLogEntryType):
|
||||
pass
|
||||
|
||||
|
||||
@log_entry_types.new_from_dict({
|
||||
'pretix.event.checkinlist.added': _('The check-in list has been added.'),
|
||||
'pretix.event.checkinlist.deleted': _('The check-in list has been deleted.'),
|
||||
'pretix.event.checkinlists.deleted': _('The check-in list has been deleted.'), # backwards compatibility
|
||||
'pretix.event.checkinlist.changed': _('The check-in list has been changed.'),
|
||||
})
|
||||
class CheckinlistLogEntryType(EventLogEntryType):
|
||||
object_link_wrapper = _('Check-in list {val}')
|
||||
object_link_viewname = 'control:event.orders.checkinlists.edit'
|
||||
object_link_argname = 'list'
|
||||
content_type = CheckinList
|
||||
|
||||
|
||||
@log_entry_types.new_from_dict({
|
||||
'pretix.event.plugins.enabled': _('The plugin has been enabled.'),
|
||||
'pretix.event.plugins.disabled': _('The plugin has been disabled.'),
|
||||
@@ -724,7 +768,7 @@ class CoreEventLogEntryType(EventLogEntryType):
|
||||
class EventPluginStateLogEntryType(EventLogEntryType):
|
||||
object_link_wrapper = _('Plugin {val}')
|
||||
|
||||
def get_object_link_info(self, logentry) -> dict:
|
||||
def get_object_link_info(self, logentry) -> Optional[dict]:
|
||||
if 'plugin' in logentry.parsed_data:
|
||||
app = app_cache.get(logentry.parsed_data['plugin'])
|
||||
if app and hasattr(app, 'PretixPluginMeta'):
|
||||
@@ -759,17 +803,17 @@ class CoreItemLogEntryType(ItemLogEntryType):
|
||||
'pretix.event.item.variation.changed': _('The variation "{value}" has been changed.'),
|
||||
})
|
||||
class VariationLogEntryType(ItemLogEntryType):
|
||||
def display(self, logentry):
|
||||
if 'value' not in logentry.parsed_data:
|
||||
def display(self, logentry, data):
|
||||
if 'value' not in data:
|
||||
# Backwards compatibility
|
||||
var = ItemVariation.objects.filter(id=logentry.parsed_data['id']).first()
|
||||
var = ItemVariation.objects.filter(id=data['id']).first()
|
||||
if var:
|
||||
logentry.parsed_data['value'] = str(var.value)
|
||||
data['value'] = str(var.value)
|
||||
else:
|
||||
logentry.parsed_data['value'] = '?'
|
||||
data['value'] = '?'
|
||||
else:
|
||||
logentry.parsed_data['value'] = LazyI18nString(logentry.parsed_data['value'])
|
||||
return super().display(logentry)
|
||||
data['value'] = LazyI18nString(data['value'])
|
||||
return super().display(logentry, data)
|
||||
|
||||
|
||||
@log_entry_types.new_from_dict({
|
||||
@@ -825,27 +869,27 @@ class CoreDiscountLogEntryType(DiscountLogEntryType):
|
||||
class LegacyCheckinLogEntryType(OrderLogEntryType):
|
||||
action_type = 'pretix.control.views.checkin'
|
||||
|
||||
def display(self, logentry):
|
||||
def display(self, logentry, data):
|
||||
# deprecated
|
||||
dt = dateutil.parser.parse(logentry.parsed_data.get('datetime'))
|
||||
dt = dateutil.parser.parse(data.get('datetime'))
|
||||
tz = logentry.event.timezone
|
||||
dt_formatted = date_format(dt.astimezone(tz), "SHORT_DATETIME_FORMAT")
|
||||
if 'list' in logentry.parsed_data:
|
||||
if 'list' in data:
|
||||
try:
|
||||
checkin_list = logentry.event.checkin_lists.get(pk=logentry.parsed_data.get('list')).name
|
||||
checkin_list = logentry.event.checkin_lists.get(pk=data.get('list')).name
|
||||
except CheckinList.DoesNotExist:
|
||||
checkin_list = _("(unknown)")
|
||||
else:
|
||||
checkin_list = _("(unknown)")
|
||||
|
||||
if logentry.parsed_data.get('first'):
|
||||
if data.get('first'):
|
||||
return _('Position #{posid} has been checked in manually at {datetime} on list "{list}".').format(
|
||||
posid=logentry.parsed_data.get('positionid'),
|
||||
posid=data.get('positionid'),
|
||||
datetime=dt_formatted,
|
||||
list=checkin_list,
|
||||
)
|
||||
return _('Position #{posid} has been checked in again at {datetime} on list "{list}".').format(
|
||||
posid=logentry.parsed_data.get('positionid'),
|
||||
posid=data.get('positionid'),
|
||||
datetime=dt_formatted,
|
||||
list=checkin_list
|
||||
)
|
||||
|
||||
@@ -491,8 +491,11 @@ class PaymentProviderSettings(EventSettingsViewMixin, EventPermissionRequiredMix
|
||||
if self.form.is_valid():
|
||||
if self.form.has_changed():
|
||||
self.request.event.log_action(
|
||||
'pretix.event.payment.provider.' + self.provider.identifier, user=self.request.user, data={
|
||||
k: self.form.cleaned_data.get(k) for k in self.form.changed_data
|
||||
'pretix.event.payment.provider', user=self.request.user, data={
|
||||
'provider': self.provider.identifier,
|
||||
'new_values': {
|
||||
k: self.form.cleaned_data.get(k) for k in self.form.changed_data
|
||||
}
|
||||
}
|
||||
)
|
||||
self.form.save()
|
||||
@@ -888,11 +891,14 @@ class TicketSettings(EventSettingsViewMixin, EventPermissionRequiredMixin, FormV
|
||||
provider.form.save()
|
||||
if provider.form.has_changed():
|
||||
self.request.event.log_action(
|
||||
'pretix.event.tickets.provider.' + provider.identifier, user=self.request.user, data={
|
||||
k: (provider.form.cleaned_data.get(k).name
|
||||
if isinstance(provider.form.cleaned_data.get(k), File)
|
||||
else provider.form.cleaned_data.get(k))
|
||||
for k in provider.form.changed_data
|
||||
'pretix.event.tickets.provider', user=self.request.user, data={
|
||||
'provider': provider.identifier,
|
||||
'new_values': {
|
||||
k: (provider.form.cleaned_data.get(k).name
|
||||
if isinstance(provider.form.cleaned_data.get(k), File)
|
||||
else provider.form.cleaned_data.get(k))
|
||||
for k in provider.form.changed_data
|
||||
}
|
||||
}
|
||||
)
|
||||
tickets.invalidate_cache.apply_async(kwargs={'event': self.request.event.pk, 'provider': provider.identifier})
|
||||
|
||||
@@ -313,7 +313,7 @@ class EventWizard(SafeSessionWizardView):
|
||||
)
|
||||
event.set_defaults()
|
||||
|
||||
if basics_data['tax_rate']:
|
||||
if basics_data['tax_rate'] is not None:
|
||||
if not event.settings.tax_rate_default or event.settings.tax_rate_default.rate != basics_data['tax_rate']:
|
||||
event.settings.tax_rate_default = event.tax_rules.create(
|
||||
name=LazyI18nString.from_gettext(gettext('VAT')),
|
||||
|
||||
@@ -8,7 +8,7 @@ msgstr ""
|
||||
"Project-Id-Version: \n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2025-01-15 16:46+0000\n"
|
||||
"PO-Revision-Date: 2024-09-10 07:17+0000\n"
|
||||
"PO-Revision-Date: 2025-01-22 16:00+0000\n"
|
||||
"Last-Translator: Raphael Michel <michel@rami.io>\n"
|
||||
"Language-Team: German <https://translate.pretix.eu/projects/pretix/pretix-js/"
|
||||
"de/>\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 5.7\n"
|
||||
"X-Generator: Weblate 5.9.2\n"
|
||||
|
||||
#: pretix/plugins/banktransfer/static/pretixplugins/banktransfer/ui.js:56
|
||||
#: pretix/plugins/banktransfer/static/pretixplugins/banktransfer/ui.js:62
|
||||
@@ -777,13 +777,13 @@ msgstr "Preis"
|
||||
#, javascript-format
|
||||
msgctxt "widget"
|
||||
msgid "Original price: %s"
|
||||
msgstr ""
|
||||
msgstr "Originalpreis: %s"
|
||||
|
||||
#: pretix/static/pretixpresale/js/widget/widget.js:21
|
||||
#, javascript-format
|
||||
msgctxt "widget"
|
||||
msgid "New price: %s"
|
||||
msgstr ""
|
||||
msgstr "Neuer Preis: %s"
|
||||
|
||||
#: pretix/static/pretixpresale/js/widget/widget.js:22
|
||||
msgctxt "widget"
|
||||
@@ -836,7 +836,7 @@ msgstr "ab %(currency)s %(price)s"
|
||||
#, javascript-format
|
||||
msgctxt "widget"
|
||||
msgid "Image of %s"
|
||||
msgstr ""
|
||||
msgstr "Bild von %s"
|
||||
|
||||
#: pretix/static/pretixpresale/js/widget/widget.js:32
|
||||
msgctxt "widget"
|
||||
|
||||
@@ -8,7 +8,7 @@ msgstr ""
|
||||
"Project-Id-Version: \n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2025-01-15 16:46+0000\n"
|
||||
"PO-Revision-Date: 2024-09-10 07:17+0000\n"
|
||||
"PO-Revision-Date: 2025-01-22 16:00+0000\n"
|
||||
"Last-Translator: Raphael Michel <michel@rami.io>\n"
|
||||
"Language-Team: German (informal) <https://translate.pretix.eu/projects/"
|
||||
"pretix/pretix-js/de_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 5.7\n"
|
||||
"X-Generator: Weblate 5.9.2\n"
|
||||
|
||||
#: pretix/plugins/banktransfer/static/pretixplugins/banktransfer/ui.js:56
|
||||
#: pretix/plugins/banktransfer/static/pretixplugins/banktransfer/ui.js:62
|
||||
@@ -776,13 +776,13 @@ msgstr "Preis"
|
||||
#, javascript-format
|
||||
msgctxt "widget"
|
||||
msgid "Original price: %s"
|
||||
msgstr ""
|
||||
msgstr "Originalpreis: %s"
|
||||
|
||||
#: pretix/static/pretixpresale/js/widget/widget.js:21
|
||||
#, javascript-format
|
||||
msgctxt "widget"
|
||||
msgid "New price: %s"
|
||||
msgstr ""
|
||||
msgstr "Neuer Preis: %s"
|
||||
|
||||
#: pretix/static/pretixpresale/js/widget/widget.js:22
|
||||
msgctxt "widget"
|
||||
@@ -835,7 +835,7 @@ msgstr "ab %(currency)s %(price)s"
|
||||
#, javascript-format
|
||||
msgctxt "widget"
|
||||
msgid "Image of %s"
|
||||
msgstr ""
|
||||
msgstr "Bild von %s"
|
||||
|
||||
#: pretix/static/pretixpresale/js/widget/widget.js:32
|
||||
msgctxt "widget"
|
||||
|
||||
@@ -8,8 +8,8 @@ msgstr ""
|
||||
"Project-Id-Version: PACKAGE VERSION\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2025-01-21 16:42+0000\n"
|
||||
"PO-Revision-Date: 2025-01-21 00:00+0000\n"
|
||||
"Last-Translator: Hector <hector@demandaeventos.es>\n"
|
||||
"PO-Revision-Date: 2025-01-22 16:00+0000\n"
|
||||
"Last-Translator: CVZ-es <damien.bremont@casadevelazquez.org>\n"
|
||||
"Language-Team: Spanish <https://translate.pretix.eu/projects/pretix/pretix/"
|
||||
"es/>\n"
|
||||
"Language: es\n"
|
||||
@@ -3430,12 +3430,12 @@ msgid ""
|
||||
"The relevant plugin is currently not active. To activate it, click here to "
|
||||
"go to the plugin settings."
|
||||
msgstr ""
|
||||
"El plugin correspondiente no está activo en este momento. Para activarlo, "
|
||||
"haga clic aquí para ir a la configuración del plugin."
|
||||
|
||||
#: pretix/base/logentrytypes.py:50
|
||||
#, fuzzy
|
||||
#| msgid "The selected ticket shop is currently not available."
|
||||
msgid "The relevant plugin is currently not active."
|
||||
msgstr "La taquilla seleccionada no está disponible en este momento."
|
||||
msgstr "El plugin correspondiente no está activado."
|
||||
|
||||
#: pretix/base/logentrytypes.py:183
|
||||
#, python-brace-format
|
||||
@@ -16818,22 +16818,17 @@ msgid "A user has been removed from the event team."
|
||||
msgstr "Un usuario ha sido eliminado del equipo de eventos."
|
||||
|
||||
#: pretix/control/logdisplay.py:721
|
||||
#, fuzzy
|
||||
#| msgid "A plugin has been enabled."
|
||||
msgid "The plugin has been enabled."
|
||||
msgstr "Se ha habilitado un plugin."
|
||||
msgstr "El plugin ha sido activado."
|
||||
|
||||
#: pretix/control/logdisplay.py:722
|
||||
#, fuzzy
|
||||
#| msgid "A plugin has been disabled."
|
||||
msgid "The plugin has been disabled."
|
||||
msgstr "Un plugin ha sido desactivado."
|
||||
msgstr "El plugin ha sido desactivado."
|
||||
|
||||
#: pretix/control/logdisplay.py:725
|
||||
#, fuzzy, python-brace-format
|
||||
#| msgid "Question {val}"
|
||||
#, python-brace-format
|
||||
msgid "Plugin {val}"
|
||||
msgstr "Pregunta {val}"
|
||||
msgstr "Plugin {val}"
|
||||
|
||||
#: pretix/control/logdisplay.py:741
|
||||
msgid "The product has been created."
|
||||
@@ -30528,10 +30523,9 @@ msgid "An email rule was deleted"
|
||||
msgstr "Se eliminó una regla de correo electrónico"
|
||||
|
||||
#: pretix/plugins/sendmail/signals.py:140
|
||||
#, fuzzy, python-brace-format
|
||||
#| msgid "Tax rule {val}"
|
||||
#, python-brace-format
|
||||
msgid "Mail rule {val}"
|
||||
msgstr "Regla de impuesto {val}"
|
||||
msgstr "Regla de correo {val}"
|
||||
|
||||
#: pretix/plugins/sendmail/templates/pretixplugins/sendmail/history.html:8
|
||||
msgid ""
|
||||
@@ -33043,7 +33037,7 @@ msgstr "El precio de este producto se redujo debido a un descuento automático."
|
||||
#: pretix/presale/templates/pretixpresale/event/fragment_cart.html:346
|
||||
#, python-format
|
||||
msgid "%(percent)s %% Discount"
|
||||
msgstr ""
|
||||
msgstr "%(percent)s %% Descuento"
|
||||
|
||||
#: pretix/presale/templates/pretixpresale/event/fragment_cart.html:277
|
||||
#: pretix/presale/templates/pretixpresale/event/fragment_cart.html:350
|
||||
|
||||
@@ -8,8 +8,8 @@ msgstr ""
|
||||
"Project-Id-Version: PACKAGE VERSION\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2025-01-21 16:42+0000\n"
|
||||
"PO-Revision-Date: 2024-12-25 23:27+0000\n"
|
||||
"Last-Translator: Aarni Heinonen <vamoosev@gmail.com>\n"
|
||||
"PO-Revision-Date: 2025-01-22 16:00+0000\n"
|
||||
"Last-Translator: Johanna Ketola <johanna.ketola@om.org>\n"
|
||||
"Language-Team: Finnish <https://translate.pretix.eu/projects/pretix/pretix/"
|
||||
"fi/>\n"
|
||||
"Language: fi\n"
|
||||
@@ -93,7 +93,7 @@ msgstr "Italia"
|
||||
|
||||
#: pretix/_base_settings.py:105
|
||||
msgid "Japanese"
|
||||
msgstr ""
|
||||
msgstr "japani"
|
||||
|
||||
#: pretix/_base_settings.py:106
|
||||
msgid "Latvian"
|
||||
@@ -2026,7 +2026,7 @@ msgid "Net at {rate} % tax"
|
||||
msgstr "Netto {rate} % arvonlisäverolla"
|
||||
|
||||
#: pretix/base/exporters/orderlist.py:277
|
||||
#, fuzzy, python-brace-format
|
||||
#, python-brace-format
|
||||
msgid "Tax value at {rate} % tax"
|
||||
msgstr "Arvonlisäveron arvo {rate} % verokannalla"
|
||||
|
||||
@@ -2051,7 +2051,6 @@ msgstr "Seurantapäivämäärä"
|
||||
#: pretix/control/templates/pretixcontrol/orders/index.html:151
|
||||
#: pretix/control/templates/pretixcontrol/organizers/customer.html:208
|
||||
#: pretix/presale/templates/pretixpresale/organizers/customer_orders.html:51
|
||||
#, fuzzy
|
||||
msgid "Positions"
|
||||
msgstr "Paikat"
|
||||
|
||||
@@ -2218,7 +2217,6 @@ msgid "Voucher"
|
||||
msgstr "Kuponki"
|
||||
|
||||
#: pretix/base/exporters/orderlist.py:610
|
||||
#, fuzzy
|
||||
msgid "Pseudonymization ID"
|
||||
msgstr "Pseudonymisointitunniste"
|
||||
|
||||
@@ -2309,7 +2307,6 @@ msgid "Invoice address country"
|
||||
msgstr "Laskutusosoitteen maa"
|
||||
|
||||
#: pretix/base/exporters/orderlist.py:652
|
||||
#, fuzzy
|
||||
msgctxt "address"
|
||||
msgid "Invoice address state"
|
||||
msgstr "Laskutusosoitteen maakunta"
|
||||
@@ -3409,12 +3406,12 @@ msgid ""
|
||||
"The relevant plugin is currently not active. To activate it, click here to "
|
||||
"go to the plugin settings."
|
||||
msgstr ""
|
||||
"Kyseinen liitännäinen ei ole tällä hetkellä käytössä. Ottaaksesi sen "
|
||||
"käyttöön, napsauta tästä ja siirry liitännäisasetuksiin."
|
||||
|
||||
#: pretix/base/logentrytypes.py:50
|
||||
#, fuzzy
|
||||
#| msgid "This product is currently not available."
|
||||
msgid "The relevant plugin is currently not active."
|
||||
msgstr "Tämä tuote ei ole juuri nyt saatavilla."
|
||||
msgstr "Tämä liitännäinen ei ole juuri nyt käytössä."
|
||||
|
||||
#: pretix/base/logentrytypes.py:183
|
||||
#, python-brace-format
|
||||
@@ -3443,9 +3440,9 @@ msgid "Quota {val}"
|
||||
msgstr "Kiintiö {val}"
|
||||
|
||||
#: pretix/base/logentrytypes.py:223
|
||||
#, fuzzy, python-brace-format
|
||||
#, python-brace-format
|
||||
msgid "Discount {val}"
|
||||
msgstr "Tuote {val}"
|
||||
msgstr "Alennus {val}"
|
||||
|
||||
#: pretix/base/logentrytypes.py:229
|
||||
#, python-brace-format
|
||||
@@ -3460,7 +3457,7 @@ msgstr "Kysymys {val}"
|
||||
#: pretix/base/logentrytypes.py:241
|
||||
#, python-brace-format
|
||||
msgid "Tax rule {val}"
|
||||
msgstr ""
|
||||
msgstr "Verotussääntö {val}"
|
||||
|
||||
#: pretix/base/media.py:71
|
||||
msgid "Barcode / QR-Code"
|
||||
@@ -5018,11 +5015,9 @@ msgstr "Jäsenyyden kesto päivinä"
|
||||
|
||||
#: pretix/base/models/items.py:712
|
||||
msgid "Membership duration in months"
|
||||
msgstr ""
|
||||
msgstr "Jäsenyyden kesto kuukausissa"
|
||||
|
||||
#: pretix/base/models/items.py:719
|
||||
#, fuzzy
|
||||
#| msgid "Valid"
|
||||
msgid "Validity"
|
||||
msgstr "Voimassa"
|
||||
|
||||
@@ -5037,58 +5032,60 @@ msgid ""
|
||||
"change the settings here later, existing tickets will not be affected by the "
|
||||
"change but keep their current validity."
|
||||
msgstr ""
|
||||
"Kun säädät asetuksia säännöllistä tapahtumaa tai sellaista tapahtumasarjaa "
|
||||
"varten, jossa on aikavälejä, tätä arvoa ei yleensä tarvitse muuttaa. "
|
||||
"Oletusasetuksella lippujen voimassaoloaika määräytyy tuotteen sijaan "
|
||||
"tapahtuman ja sisäänkirjautumisasetusten perusteella. Käytä muita "
|
||||
"vaihtoehtoja vain, jos tarvitset niitä esimerkiksi mahdollistaaksesi "
|
||||
"sellaisen lipun varauksen, joka on vuoden voimassa ja jonka aloituspäivä on "
|
||||
"dynaaminen. Huomaa, että voimassaolo tallennetaan lipun tietoihin, joten jos "
|
||||
"muutat asetuksia myöhemmin, muutos ei vaikuta jo olemassa oleviin lippuihin, "
|
||||
"vaan ne säilyttävät nykyisen voimassaoloaikansa."
|
||||
|
||||
#: pretix/base/models/items.py:729 pretix/control/forms/item.py:728
|
||||
#, fuzzy
|
||||
#| msgid "Start of presale"
|
||||
msgid "Start of validity"
|
||||
msgstr "Ennakkomyynnin alku"
|
||||
msgstr "Voimassaoloajan alku"
|
||||
|
||||
#: pretix/base/models/items.py:730
|
||||
#, fuzzy
|
||||
#| msgid "End of presale"
|
||||
msgid "End of validity"
|
||||
msgstr "Ennakkomyynnin loppu"
|
||||
msgstr "Voimassaoloajan loppu"
|
||||
|
||||
#: pretix/base/models/items.py:733
|
||||
msgid "Minutes"
|
||||
msgstr ""
|
||||
msgstr "Minuuttia"
|
||||
|
||||
#: pretix/base/models/items.py:737
|
||||
msgid "Hours"
|
||||
msgstr ""
|
||||
msgstr "Tuntia"
|
||||
|
||||
#: pretix/base/models/items.py:741
|
||||
msgid "Days"
|
||||
msgstr ""
|
||||
msgstr "Päivää"
|
||||
|
||||
#: pretix/base/models/items.py:745
|
||||
#, fuzzy
|
||||
#| msgid "Month"
|
||||
msgid "Months"
|
||||
msgstr "Kuukausi"
|
||||
msgstr "Kuukautta"
|
||||
|
||||
#: pretix/base/models/items.py:748
|
||||
msgid "Customers can select the validity start date"
|
||||
msgstr ""
|
||||
msgstr "Asiakkaat voivat valita ensimmäisen voimassaolopäivän"
|
||||
|
||||
#: pretix/base/models/items.py:749
|
||||
msgid "If not selected, the validity always starts at the time of purchase."
|
||||
msgstr ""
|
||||
msgstr "Jos tätä ei ole valittu, voimassaoloaika alkaa aina ostohetkellä."
|
||||
|
||||
#: pretix/base/models/items.py:754
|
||||
#, fuzzy
|
||||
#| msgid "Maximum usages"
|
||||
msgid "Maximum future start"
|
||||
msgstr "Enimmäiskäyttökerrat"
|
||||
msgstr "Kaukaisin mahdollinen aloituspäivä tulevaisuudessa"
|
||||
|
||||
#: pretix/base/models/items.py:755
|
||||
msgid "The selected start date may only be this many days in the future."
|
||||
msgstr ""
|
||||
"Valittu aloituspäivä saa olla enintään näin monta päivää tulevaisuudessa."
|
||||
|
||||
#: pretix/base/models/items.py:761
|
||||
msgid "Reusable media policy"
|
||||
msgstr ""
|
||||
msgstr "Uudelleenkäytettävän median käytänteet"
|
||||
|
||||
#: pretix/base/models/items.py:763
|
||||
msgid ""
|
||||
@@ -5099,10 +5096,16 @@ msgid ""
|
||||
"feature that also requires specific configuration of ticketing and printing "
|
||||
"settings."
|
||||
msgstr ""
|
||||
"Jos tämä tuote on tarkoitus tallentaa uudelleenkäytettävälle fyysiselle "
|
||||
"välineelle, voit liittää siihen fyysisen välineen käytänteet. Tätä ei "
|
||||
"tarvita tavallisille lipuille, jotka käyttävät kertakäyttöistä viivakoodia, "
|
||||
"vaan ainoastaan tuotteille kuten uudelleenladattavat kausikortit tai "
|
||||
"ladattavat lahjakorttirannekkeet. Tämä on edistynyt ominaisuus, joka vaatii "
|
||||
"myös erityisiä asetuksia lipunmyynnin ja tulostusasetusten osalta."
|
||||
|
||||
#: pretix/base/models/items.py:773
|
||||
msgid "Reusable media type"
|
||||
msgstr ""
|
||||
msgstr "Uudelleenkäytettävän median tyyppi"
|
||||
|
||||
#: pretix/base/models/items.py:775
|
||||
msgid ""
|
||||
@@ -5178,9 +5181,8 @@ msgid "This is shown below the variation name in lists."
|
||||
msgstr ""
|
||||
|
||||
#: pretix/base/models/items.py:1171
|
||||
#, fuzzy
|
||||
msgid "Require approval"
|
||||
msgstr "Uusi tilaus vaatii hyväksynnän"
|
||||
msgstr "Vaatii hyväksynnän"
|
||||
|
||||
#: pretix/base/models/items.py:1173
|
||||
msgid ""
|
||||
@@ -5216,9 +5218,8 @@ msgid ""
|
||||
msgstr ""
|
||||
|
||||
#: pretix/base/models/items.py:1224
|
||||
#, fuzzy
|
||||
msgid "Show only if a matching voucher is redeemed."
|
||||
msgstr "Montako kertaa tämän kupongin voi käyttää."
|
||||
msgstr "Näytä vain, jos vastaava alennuskoodi lunastetaan."
|
||||
|
||||
#: pretix/base/models/items.py:1226
|
||||
msgid ""
|
||||
@@ -5417,10 +5418,8 @@ msgid "Maximum value"
|
||||
msgstr "Suurin arvo"
|
||||
|
||||
#: pretix/base/models/items.py:1740
|
||||
#, fuzzy
|
||||
#| msgid "Maximum value"
|
||||
msgid "Maximum length"
|
||||
msgstr "Suurin arvo"
|
||||
msgstr "Enimmäispituus"
|
||||
|
||||
#: pretix/base/models/items.py:1746
|
||||
msgid "Validate file to be a portrait"
|
||||
@@ -5437,10 +5436,8 @@ msgid "An answer to this question is required to proceed."
|
||||
msgstr ""
|
||||
|
||||
#: pretix/base/models/items.py:1812
|
||||
#, fuzzy
|
||||
#| msgid "Event type"
|
||||
msgid "Invalid input type."
|
||||
msgstr "Tapahtuman tyyppi"
|
||||
msgstr "Virheellinen syötetyyppi."
|
||||
|
||||
#: pretix/base/models/items.py:1846
|
||||
msgid "The number is to low."
|
||||
@@ -5577,10 +5574,8 @@ msgid "Subevent cannot be null for event series."
|
||||
msgstr ""
|
||||
|
||||
#: pretix/base/models/items.py:2208
|
||||
#, fuzzy
|
||||
#| msgid "Purchased products"
|
||||
msgid "Required for products"
|
||||
msgstr "Ostetut tuotteet"
|
||||
msgstr "Pakollinen tuotteille"
|
||||
|
||||
#: pretix/base/models/items.py:2209
|
||||
msgid ""
|
||||
@@ -5693,10 +5688,8 @@ msgid "Meta information"
|
||||
msgstr ""
|
||||
|
||||
#: pretix/base/models/orders.py:305
|
||||
#, fuzzy
|
||||
#| msgid "Payment information"
|
||||
msgid "API meta information"
|
||||
msgstr "Maksutiedot"
|
||||
msgstr "API:n metatiedot"
|
||||
|
||||
#: pretix/base/models/orders.py:414 pretix/plugins/sendmail/forms.py:236
|
||||
#: pretix/plugins/sendmail/forms.py:391 pretix/plugins/sendmail/views.py:269
|
||||
@@ -5704,17 +5697,13 @@ msgid "approval pending"
|
||||
msgstr "Odottaa hyväksyntää"
|
||||
|
||||
#: pretix/base/models/orders.py:416
|
||||
#, fuzzy
|
||||
#| msgid "Pending (overdue)"
|
||||
msgctxt "order state"
|
||||
msgid "pending (confirmed)"
|
||||
msgstr "Odottaa (erääntynyt)"
|
||||
msgstr "odottaa (vahvistettu)"
|
||||
|
||||
#: pretix/base/models/orders.py:418
|
||||
#, fuzzy
|
||||
#| msgid "Canceled (fully)"
|
||||
msgid "canceled (paid fee)"
|
||||
msgstr "Peruttu (kokonaan)"
|
||||
msgstr "peruutettu (maksettu maksu)"
|
||||
|
||||
#: pretix/base/models/orders.py:1031
|
||||
msgid ""
|
||||
@@ -5874,10 +5863,8 @@ msgid "Insurance fee"
|
||||
msgstr ""
|
||||
|
||||
#: pretix/base/models/orders.py:2289
|
||||
#, fuzzy
|
||||
#| msgid "Other fees"
|
||||
msgid "Late fee"
|
||||
msgstr "Muut maksut"
|
||||
msgstr "Myöhästynyt maksu"
|
||||
|
||||
#: pretix/base/models/orders.py:2290
|
||||
msgid "Other fees"
|
||||
@@ -5939,9 +5926,8 @@ msgid "Ticket"
|
||||
msgstr ""
|
||||
|
||||
#: pretix/base/models/orders.py:3463
|
||||
#, fuzzy
|
||||
msgid "Certificate"
|
||||
msgstr "Variaatiot"
|
||||
msgstr "Todistus"
|
||||
|
||||
#: pretix/base/models/orders.py:3464 pretix/control/views/event.py:369
|
||||
#: pretix/control/views/event.py:374
|
||||
@@ -6006,10 +5992,8 @@ msgid "Can manage customer accounts"
|
||||
msgstr "Voi hallita asiakastilejä"
|
||||
|
||||
#: pretix/base/models/organizer.py:315
|
||||
#, fuzzy
|
||||
#| msgid "Can manage customer accounts"
|
||||
msgid "Can manage reusable media"
|
||||
msgstr "Voi hallita asiakastilejä"
|
||||
msgstr "Voi hallita uudelleenkäytettävää mediaa"
|
||||
|
||||
#: pretix/base/models/organizer.py:319
|
||||
msgid "Can manage gift cards"
|
||||
@@ -6072,10 +6056,8 @@ msgstr ""
|
||||
|
||||
#: pretix/base/models/organizer.py:538
|
||||
#: pretix/control/templates/pretixcontrol/organizers/channels.html:23
|
||||
#, fuzzy
|
||||
#| msgid "External identifier"
|
||||
msgid "Identifier"
|
||||
msgstr "Ulkoinen tunniste"
|
||||
msgstr "Tunnus"
|
||||
|
||||
#: pretix/base/models/organizer.py:548
|
||||
#: pretix/control/templates/pretixcontrol/boxoffice/payment.html:54
|
||||
@@ -6113,9 +6095,8 @@ msgid "Seat {number}"
|
||||
msgstr ""
|
||||
|
||||
#: pretix/base/models/tax.py:144
|
||||
#, fuzzy
|
||||
msgid "Standard rates"
|
||||
msgstr "Lisää kalenteriin"
|
||||
msgstr "Vakiohinnat"
|
||||
|
||||
#: pretix/base/models/tax.py:148
|
||||
msgctxt "tax_code"
|
||||
@@ -6123,11 +6104,9 @@ msgid "Standard rate"
|
||||
msgstr ""
|
||||
|
||||
#: pretix/base/models/tax.py:152
|
||||
#, fuzzy
|
||||
#| msgid "Reduced ticket"
|
||||
msgctxt "tax_code"
|
||||
msgid "Reduced rate"
|
||||
msgstr "Alennuslippu"
|
||||
msgstr "Alennettu hinta"
|
||||
|
||||
#: pretix/base/models/tax.py:156
|
||||
msgctxt "tax_code"
|
||||
@@ -6141,10 +6120,8 @@ msgid "Reverse charge"
|
||||
msgstr ""
|
||||
|
||||
#: pretix/base/models/tax.py:168
|
||||
#, fuzzy
|
||||
#| msgid "Tax rate"
|
||||
msgid "Tax free"
|
||||
msgstr "Veroprosentti"
|
||||
msgstr "Veroton"
|
||||
|
||||
#: pretix/base/models/tax.py:171
|
||||
msgctxt "tax_code"
|
||||
@@ -6254,10 +6231,8 @@ msgid ""
|
||||
msgstr ""
|
||||
|
||||
#: pretix/base/models/tax.py:314
|
||||
#, fuzzy
|
||||
#| msgid "Login was not successful. Error message: \"{error}\"."
|
||||
msgid "Your set of rules is not valid. Error message: {}"
|
||||
msgstr "Sisäänkirjautuminen ei onnistunut. Virheilmoitus: \"{error}\"."
|
||||
msgstr "Sääntöjoukkosi ei ole kelvollinen. Virheilmoitus: {}"
|
||||
|
||||
#: pretix/base/models/tax.py:325
|
||||
msgid "Official name"
|
||||
@@ -6269,10 +6244,8 @@ msgstr ""
|
||||
|
||||
#: pretix/base/models/tax.py:330 pretix/control/forms/event.py:1509
|
||||
#: pretix/control/templates/pretixcontrol/order/transactions.html:22
|
||||
#, fuzzy
|
||||
#| msgid "ZIP code"
|
||||
msgid "Tax code"
|
||||
msgstr "Postinumero"
|
||||
msgstr "Verokoodi"
|
||||
|
||||
#: pretix/base/models/tax.py:331
|
||||
msgid ""
|
||||
@@ -6468,10 +6441,8 @@ msgid ""
|
||||
msgstr ""
|
||||
|
||||
#: pretix/base/models/vouchers.py:348
|
||||
#, fuzzy
|
||||
#| msgid "You cannot select a quota that belongs to a different event."
|
||||
msgid "You cannot select a product that belongs to a different event."
|
||||
msgstr "Et voi valita kiintiötä, joka kuuluu eri tapahtumaan."
|
||||
msgstr "Et voi valita tuotetta, joka kuuluu eri tapahtumaan."
|
||||
|
||||
#: pretix/base/models/vouchers.py:350 pretix/base/models/vouchers.py:360
|
||||
msgid ""
|
||||
@@ -6719,11 +6690,11 @@ msgid ""
|
||||
msgstr ""
|
||||
|
||||
#: pretix/base/payment.py:342
|
||||
#, fuzzy
|
||||
#| msgid "This variation will not be sold before the given date."
|
||||
msgid ""
|
||||
"Users will not be able to choose this payment provider before the given date."
|
||||
msgstr "Tätä variaatiota ei myydä ennen annettu ajankohtaa."
|
||||
msgstr ""
|
||||
"Käyttäjät eivät voi valita tätä maksupalveluntarjoajaa ennen annettua "
|
||||
"päivämäärää."
|
||||
|
||||
#: pretix/base/payment.py:347
|
||||
msgid "Minimum order total"
|
||||
@@ -6923,10 +6894,8 @@ msgid "Balanced against orders: %s"
|
||||
msgstr ""
|
||||
|
||||
#: pretix/base/payment.py:1328
|
||||
#, fuzzy
|
||||
#| msgid "Payment method"
|
||||
msgid "Payment method description"
|
||||
msgstr "Maksutapa"
|
||||
msgstr "Maksutavan kuvaus"
|
||||
|
||||
#: pretix/base/payment.py:1345
|
||||
msgid "In test mode, only test cards will work."
|
||||
@@ -7154,10 +7123,8 @@ msgid "20:00"
|
||||
msgstr ""
|
||||
|
||||
#: pretix/base/pdf.py:265
|
||||
#, fuzzy
|
||||
#| msgid "Event end"
|
||||
msgid "Event begin weekday"
|
||||
msgstr "Tapahtuma päättyy"
|
||||
msgstr "Tapahtuma alkamisviikonpäivä"
|
||||
|
||||
#: pretix/base/pdf.py:266 pretix/base/pdf.py:295
|
||||
#: pretix/base/services/checkin.py:362 pretix/control/forms/filter.py:1234
|
||||
@@ -7177,10 +7144,8 @@ msgid "22:00"
|
||||
msgstr ""
|
||||
|
||||
#: pretix/base/pdf.py:294
|
||||
#, fuzzy
|
||||
#| msgid "Event end time"
|
||||
msgid "Event end weekday"
|
||||
msgstr "Tapahtuman loppumisajankohta"
|
||||
msgstr "Tapahtuman loppumisviikonpäivä"
|
||||
|
||||
#: pretix/base/pdf.py:299
|
||||
msgid "Event admission date and time"
|
||||
@@ -7281,58 +7246,40 @@ msgid "Printing time"
|
||||
msgstr ""
|
||||
|
||||
#: pretix/base/pdf.py:411 pretix/control/forms/item.py:730
|
||||
#, fuzzy
|
||||
#| msgid "Purchased products"
|
||||
msgid "Purchase date"
|
||||
msgstr "Ostetut tuotteet"
|
||||
msgstr "Oston päivämäärä"
|
||||
|
||||
#: pretix/base/pdf.py:419
|
||||
#, fuzzy
|
||||
#| msgid "Purchased products"
|
||||
msgid "Purchase date and time"
|
||||
msgstr "Ostetut tuotteet"
|
||||
msgstr "Oston päivämäärä ja aika"
|
||||
|
||||
#: pretix/base/pdf.py:427
|
||||
#, fuzzy
|
||||
#| msgid "Purchased products"
|
||||
msgid "Purchase time"
|
||||
msgstr "Ostetut tuotteet"
|
||||
msgstr "Oston kellonaika"
|
||||
|
||||
#: pretix/base/pdf.py:435
|
||||
#, fuzzy
|
||||
#| msgid "Valid from"
|
||||
msgid "Validity start date"
|
||||
msgstr "Voimassa alkaen"
|
||||
msgstr "Ensimmäinen voimassaolopäivä"
|
||||
|
||||
#: pretix/base/pdf.py:443
|
||||
#, fuzzy
|
||||
#| msgid "Valid from"
|
||||
msgid "Validity start date and time"
|
||||
msgstr "Voimassa alkaen"
|
||||
msgstr "Ensimmäinen voimassaolopäivä ja -aika"
|
||||
|
||||
#: pretix/base/pdf.py:451
|
||||
#, fuzzy
|
||||
#| msgid "Valid from"
|
||||
msgid "Validity start time"
|
||||
msgstr "Voimassa alkaen"
|
||||
msgstr "Voimassaolon alkamisaika"
|
||||
|
||||
#: pretix/base/pdf.py:459
|
||||
#, fuzzy
|
||||
#| msgid "Valid from"
|
||||
msgid "Validity end date"
|
||||
msgstr "Voimassa alkaen"
|
||||
msgstr "Viimeinen voimassaolopäivä"
|
||||
|
||||
#: pretix/base/pdf.py:467
|
||||
#, fuzzy
|
||||
#| msgid "Valid from"
|
||||
msgid "Validity end date and time"
|
||||
msgstr "Voimassa alkaen"
|
||||
msgstr "Viimeinen voimassaolopäivä ja -aika"
|
||||
|
||||
#: pretix/base/pdf.py:475
|
||||
#, fuzzy
|
||||
#| msgid "Valid from"
|
||||
msgid "Validity end time"
|
||||
msgstr "Voimassa alkaen"
|
||||
msgstr "Voimassaolon päättyminen"
|
||||
|
||||
#: pretix/base/pdf.py:483
|
||||
msgid "Reusable Medium ID"
|
||||
|
||||
@@ -4,7 +4,7 @@ msgstr ""
|
||||
"Project-Id-Version: 1\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2025-01-21 16:42+0000\n"
|
||||
"PO-Revision-Date: 2025-01-17 15:39+0000\n"
|
||||
"PO-Revision-Date: 2025-01-22 16:00+0000\n"
|
||||
"Last-Translator: CVZ-es <damien.bremont@casadevelazquez.org>\n"
|
||||
"Language-Team: French <https://translate.pretix.eu/projects/pretix/pretix/fr/"
|
||||
">\n"
|
||||
@@ -3437,12 +3437,12 @@ msgid ""
|
||||
"The relevant plugin is currently not active. To activate it, click here to "
|
||||
"go to the plugin settings."
|
||||
msgstr ""
|
||||
"Le plugin concerné n'est actuellement pas actif. Pour l'activer, cliquez ici "
|
||||
"pour accéder aux paramètres du plugin."
|
||||
|
||||
#: pretix/base/logentrytypes.py:50
|
||||
#, fuzzy
|
||||
#| msgid "The selected ticket shop is currently not available."
|
||||
msgid "The relevant plugin is currently not active."
|
||||
msgstr "La billetterie sélectionnée n'est actuellement pas disponible."
|
||||
msgstr "Le plugin correspondant n'est pas activé."
|
||||
|
||||
#: pretix/base/logentrytypes.py:183
|
||||
#, python-brace-format
|
||||
@@ -16952,22 +16952,17 @@ msgid "A user has been removed from the event team."
|
||||
msgstr "Un utilisateur a été retiré de l'équipe d'événement."
|
||||
|
||||
#: pretix/control/logdisplay.py:721
|
||||
#, fuzzy
|
||||
#| msgid "A plugin has been enabled."
|
||||
msgid "The plugin has been enabled."
|
||||
msgstr "Un plugin a été activé."
|
||||
msgstr "Le plugin a été activé."
|
||||
|
||||
#: pretix/control/logdisplay.py:722
|
||||
#, fuzzy
|
||||
#| msgid "A plugin has been disabled."
|
||||
msgid "The plugin has been disabled."
|
||||
msgstr "Un plugin a été désactivé."
|
||||
msgstr "Le plugin a été désactivé."
|
||||
|
||||
#: pretix/control/logdisplay.py:725
|
||||
#, fuzzy, python-brace-format
|
||||
#| msgid "Question {val}"
|
||||
#, python-brace-format
|
||||
msgid "Plugin {val}"
|
||||
msgstr "Question {val}"
|
||||
msgstr "Plugin {val}"
|
||||
|
||||
#: pretix/control/logdisplay.py:741
|
||||
msgid "The product has been created."
|
||||
@@ -30778,10 +30773,9 @@ msgid "An email rule was deleted"
|
||||
msgstr "Une règle d’e-mail a été supprimée"
|
||||
|
||||
#: pretix/plugins/sendmail/signals.py:140
|
||||
#, fuzzy, python-brace-format
|
||||
#| msgid "Tax rule {val}"
|
||||
#, python-brace-format
|
||||
msgid "Mail rule {val}"
|
||||
msgstr "Règle fiscale {val}"
|
||||
msgstr "Règle de messagerie {val}"
|
||||
|
||||
#: pretix/plugins/sendmail/templates/pretixplugins/sendmail/history.html:8
|
||||
msgid ""
|
||||
@@ -33314,7 +33308,7 @@ msgstr "Le prix de ce produit a été réduit en raison d’une remise automatiq
|
||||
#: pretix/presale/templates/pretixpresale/event/fragment_cart.html:346
|
||||
#, python-format
|
||||
msgid "%(percent)s %% Discount"
|
||||
msgstr ""
|
||||
msgstr "%(percent)s %% Remise"
|
||||
|
||||
#: pretix/presale/templates/pretixpresale/event/fragment_cart.html:277
|
||||
#: pretix/presale/templates/pretixpresale/event/fragment_cart.html:350
|
||||
|
||||
@@ -8,7 +8,7 @@ msgstr ""
|
||||
"Project-Id-Version: PACKAGE VERSION\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2025-01-21 16:42+0000\n"
|
||||
"PO-Revision-Date: 2025-01-21 12:00+0000\n"
|
||||
"PO-Revision-Date: 2025-01-22 16:00+0000\n"
|
||||
"Last-Translator: Hijiri Umemoto <hijiri@umemoto.org>\n"
|
||||
"Language-Team: Japanese <https://translate.pretix.eu/projects/pretix/pretix/"
|
||||
"ja/>\n"
|
||||
@@ -19476,8 +19476,8 @@ msgid ""
|
||||
"JavaScript is disabled in your browser. To access our ticket shop without "
|
||||
"JavaScript, please <a %(a_attr)s>click here</a>."
|
||||
msgstr ""
|
||||
"お使いのブラウザでJavaScriptが無効になっています。JavaScriptを使用せずに当社"
|
||||
"のチケットショップにアクセスするには、%(a_attr)sをクリックしてください。"
|
||||
"ブラウザでJavaScriptが無効になっています。チケットショップへのアクセスは、 "
|
||||
"<a %(a_attr)s> ここをクリックl&t;/a> してください。"
|
||||
|
||||
#: pretix/control/templates/pretixcontrol/event/widget.html:64
|
||||
#: pretix/plugins/returnurl/templates/returnurl/settings.html:15
|
||||
|
||||
Reference in New Issue
Block a user