Compare commits

...

4 Commits

Author SHA1 Message Date
Mira Weller
35892bc186 Register missing LogEntryTypes 2025-01-24 16:36:43 +01:00
Mira
ca8d253114 Bugfixes for LogEntryTypes refactoring (#4778) 2025-01-24 16:19:55 +01:00
Mira Weller
f014a9bbd3 Reapply "Implement hidden_if_item_available_mode option (Z#23177008) (#4776)"
This reverts commit 5cd7959e86.
2025-01-24 14:48:28 +01:00
Mira Weller
3e5bfb44d2 Revert "Preliminary migration"
This reverts commit 1736efbdc3.
2025-01-24 14:48:28 +01:00
13 changed files with 58 additions and 29 deletions

View File

@@ -69,6 +69,10 @@ hidden_if_available integer **DEPRECATED*
hidden_if_item_available integer The internal ID of a different item, or ``null``. If
set, this item won't be shown publicly as long as this
other item is available.
hidden_if_item_available_mode string If ``hide`` (the default), this item is hidden in the shop
if unavailable due to the ``hidden_if_item_available`` setting.
If ``info``, the item is visible, but can't be purchased,
and a note explaining the unavailability is displayed.
require_voucher boolean If ``true``, this item can only be bought using a
voucher that is specifically assigned to this item.
hide_without_voucher boolean If ``true``, this item is only shown during the voucher
@@ -239,6 +243,10 @@ meta_data object Values set fo
The ``hidden_if_item_available`` attributes has been added, the ``hidden_if_available`` attribute has been
deprecated.
.. versionchanged:: 2025.01
The ``hidden_if_item_available_mode`` attributes has been added.
Notes
-----
@@ -308,6 +316,7 @@ Endpoints
"available_until_mode": "hide",
"hidden_if_available": null,
"hidden_if_item_available": null,
"hidden_if_item_available_mode": "hide",
"require_voucher": false,
"hide_without_voucher": false,
"allow_cancel": true,
@@ -459,6 +468,7 @@ Endpoints
"available_until_mode": "hide",
"hidden_if_available": null,
"hidden_if_item_available": null,
"hidden_if_item_available_mode": "hide",
"require_voucher": false,
"hide_without_voucher": false,
"allow_cancel": true,
@@ -589,6 +599,7 @@ Endpoints
"available_until_mode": "hide",
"hidden_if_available": null,
"hidden_if_item_available": null,
"hidden_if_item_available_mode": "hide",
"require_voucher": false,
"hide_without_voucher": false,
"allow_cancel": true,
@@ -705,6 +716,7 @@ Endpoints
"available_until_mode": "hide",
"hidden_if_available": null,
"hidden_if_item_available": null,
"hidden_if_item_available_mode": "hide",
"require_voucher": false,
"hide_without_voucher": false,
"allow_cancel": true,
@@ -855,6 +867,7 @@ Endpoints
"available_until_mode": "hide",
"hidden_if_available": null,
"hidden_if_item_available": null,
"hidden_if_item_available_mode": "hide",
"require_voucher": false,
"hide_without_voucher": false,
"generate_tickets": null,

View File

@@ -272,7 +272,7 @@ class ItemSerializer(SalesChannelMigrationMixin, I18nAwareModelSerializer):
'require_voucher', 'hide_without_voucher', 'allow_cancel', 'require_bundling',
'min_per_order', 'max_per_order', 'checkin_attention', 'checkin_text', 'has_variations', 'variations',
'addons', 'bundles', 'original_price', 'require_approval', 'generate_tickets',
'show_quota_left', 'hidden_if_available', 'hidden_if_item_available', 'allow_waitinglist',
'show_quota_left', 'hidden_if_available', 'hidden_if_item_available', 'hidden_if_item_available_mode', 'allow_waitinglist',
'issue_giftcard', 'meta_data',
'require_membership', 'require_membership_types', 'require_membership_hidden', 'grant_membership_type',
'grant_membership_duration_like_event', 'grant_membership_duration_days',

View File

@@ -13,6 +13,6 @@ class Migration(migrations.Migration):
migrations.AddField(
model_name="item",
name="hidden_if_item_available_mode",
field=models.CharField(default="hide", max_length=16, null=True),
field=models.CharField(default="hide", max_length=16),
),
]

View File

@@ -442,8 +442,12 @@ class Item(LoggedModel):
UNAVAIL_MODE_INFO = "info"
UNAVAIL_MODES = (
(UNAVAIL_MODE_HIDDEN, _("Hide product if unavailable")),
(UNAVAIL_MODE_INFO, _("Show info text if unavailable")),
(UNAVAIL_MODE_INFO, _("Show product with info on why its unavailable")),
)
UNAVAIL_MODE_ICONS = {
UNAVAIL_MODE_HIDDEN: 'eye-slash',
UNAVAIL_MODE_INFO: 'info'
}
MEDIA_POLICY_REUSE = 'reuse'
MEDIA_POLICY_NEW = 'new'
@@ -596,6 +600,11 @@ class Item(LoggedModel):
"be a short period in which both products are visible while all tickets of the referenced "
"product are reserved, but not yet sold.")
)
hidden_if_item_available_mode = models.CharField(
choices=UNAVAIL_MODES,
default=UNAVAIL_MODE_HIDDEN,
max_length=16,
)
require_voucher = models.BooleanField(
verbose_name=_('This product can only be bought using a voucher.'),
default=False,
@@ -885,6 +894,8 @@ class Item(LoggedModel):
return 'available_from'
elif subevent_item and subevent_item.available_until and subevent_item.available_until < now_dt:
return 'available_until'
elif self.hidden_if_item_available and self._dependency_available:
return 'hidden_if_item_available'
else:
return None

View File

@@ -476,6 +476,7 @@ class ItemCreateForm(I18nModelForm):
'show_quota_left',
'hidden_if_available',
'hidden_if_item_available',
'hidden_if_item_available_mode',
'require_bundling',
'require_membership',
'grant_membership_type',
@@ -646,18 +647,12 @@ class ItemUpdateForm(I18nModelForm):
self.fields['available_from_mode'].widget = ButtonGroupRadioSelect(
choices=self.fields['available_from_mode'].choices,
option_icons={
Item.UNAVAIL_MODE_HIDDEN: 'eye-slash',
Item.UNAVAIL_MODE_INFO: 'info'
}
option_icons=Item.UNAVAIL_MODE_ICONS
)
self.fields['available_until_mode'].widget = ButtonGroupRadioSelect(
choices=self.fields['available_until_mode'].choices,
option_icons={
Item.UNAVAIL_MODE_HIDDEN: 'eye-slash',
Item.UNAVAIL_MODE_INFO: 'info'
}
option_icons=Item.UNAVAIL_MODE_ICONS
)
self.fields['hide_without_voucher'].widget = ButtonGroupRadioSelect(
@@ -672,6 +667,11 @@ class ItemUpdateForm(I18nModelForm):
attrs={'data-checkbox-dependency': '#id_require_voucher'}
)
self.fields['hidden_if_item_available_mode'].widget = ButtonGroupRadioSelect(
choices=self.fields['hidden_if_item_available_mode'].choices,
option_icons=Item.UNAVAIL_MODE_ICONS
)
if self.instance.hidden_if_available_id:
self.fields['hidden_if_available'].queryset = self.event.quotas.all()
self.fields['hidden_if_available'].help_text = format_html(
@@ -853,6 +853,7 @@ class ItemUpdateForm(I18nModelForm):
'show_quota_left',
'hidden_if_available',
'hidden_if_item_available',
'hidden_if_item_available_mode',
'issue_giftcard',
'require_membership',
'require_membership_types',
@@ -970,18 +971,12 @@ class ItemVariationForm(I18nModelForm):
self.fields['available_from_mode'].widget = ButtonGroupRadioSelect(
choices=self.fields['available_from_mode'].choices,
option_icons={
Item.UNAVAIL_MODE_HIDDEN: 'eye-slash',
Item.UNAVAIL_MODE_INFO: 'info'
}
option_icons=Item.UNAVAIL_MODE_ICONS
)
self.fields['available_until_mode'].widget = ButtonGroupRadioSelect(
choices=self.fields['available_until_mode'].choices,
option_icons={
Item.UNAVAIL_MODE_HIDDEN: 'eye-slash',
Item.UNAVAIL_MODE_INFO: 'info'
}
option_icons=Item.UNAVAIL_MODE_ICONS
)
self.meta_fields = []

View File

@@ -338,7 +338,7 @@ class CheckinErrorLogEntryType(OrderLogEntryType):
else:
data['list'] = _("(unknown)")
data['barcode'] = data.get('barcode')[:16]
data['barcode'] = data.get('barcode', '')[:16]
data['posid'] = logentry.parsed_data.get('positionid', '?')
if 'datetime' in data:
@@ -351,6 +351,7 @@ class CheckinErrorLogEntryType(OrderLogEntryType):
return str(plain_without_dt).format_map(data)
@log_entry_types.new('pretix.event.checkin')
class CheckinLogEntryType(CheckinErrorLogEntryType):
def display(self, logentry: LogEntry, data):
if data.get('type') == Checkin.TYPE_EXIT:
@@ -377,6 +378,7 @@ class CheckinLogEntryType(CheckinErrorLogEntryType):
)
@log_entry_types.new()
class OrderConsentLogEntryType(OrderLogEntryType):
action_type = 'pretix.event.order.consent'
@@ -386,6 +388,7 @@ class OrderConsentLogEntryType(OrderLogEntryType):
)
@log_entry_types.new()
class OrderCanceledLogEntryType(OrderLogEntryType):
action_type = 'pretix.event.order.canceled'
@@ -397,6 +400,7 @@ class OrderCanceledLogEntryType(OrderLogEntryType):
return _('The order has been canceled.')
@log_entry_types.new()
class OrderPrintLogEntryType(OrderLogEntryType):
action_type = 'pretix.event.order.print'
@@ -529,7 +533,7 @@ class VoucherRedeemedLogEntryType(VoucherLogEntryType):
})
return format_html(
self.plain,
order_code=format_html('<a href="{}">{}</a>', url, data('order_code', '?')),
order_code=format_html('<a href="{}">{}</a>', url, data.get('order_code', '?')),
)

View File

@@ -172,7 +172,7 @@
{% if form.hidden_if_available %}
{% bootstrap_field form.hidden_if_available layout="control" horizontal_field_class="col-md-7" %}
{% endif %}
{% bootstrap_field form.hidden_if_item_available layout="control" horizontal_field_class="col-md-7" %}
{% bootstrap_field form.hidden_if_item_available visibility_field=form.hidden_if_item_available_mode layout="control_with_visibility" %}
</fieldset>
{% for v in formsets.values %}
<fieldset>

View File

@@ -2,5 +2,5 @@
{% if mode == "hide" %}
<span class="pull-right text-muted unavail-mode-indicator" data-toggle="tooltip" title="{% trans "Hide product if unavailable" %}. {% if f.variation %}{% trans "You can change this option in the variation settings." %}{% else %}{% trans "You can change this option in the product settings." %}{% endif %}"><span class="fa fa-eye-slash"></span></span>
{% else %}
<span class="pull-right text-muted unavail-mode-indicator" data-toggle="tooltip" title="{% trans "Show info text if unavailable" %}. {% if f.variation %}{% trans "You can change this option in the variation settings." %}{% else %}{% trans "You can change this option in the product settings." %}{% endif %}"><span class="fa fa-info-circle"></span></span>
<span class="pull-right text-muted unavail-mode-indicator" data-toggle="tooltip" title="{% trans "Show product with info on why its unavailable" %}. {% if f.variation %}{% trans "You can change this option in the variation settings." %}{% else %}{% trans "You can change this option in the product settings." %}{% endif %}"><span class="fa fa-info-circle"></span></span>
{% endif %}

View File

@@ -51,8 +51,8 @@ def register_payment_provider(sender, **kwargs):
class PaypalEventLogEntryType(EventLogEntryType):
action_type = 'pretix.plugins.paypal.event'
def display(self, logentry):
event_type = logentry.parsed_data.get('event_type')
def display(self, logentry, data):
event_type = data.get('event_type')
text = None
plains = {
'PAYMENT.SALE.COMPLETED': _('Payment completed.'),

View File

@@ -5,6 +5,10 @@
<div class="col-md-2 col-sm-3 col-xs-6 availability-box unavailable">
<p><small><a href="#voucher">{% trans "Enter a voucher code below to buy this product." %}</a></small></p>
</div>
{% elif item.current_unavailability_reason == 'hidden_if_item_available' %}
<div class="col-md-2 col-sm-3 col-xs-6 availability-box unavailable">
<p><small>{% trans "Not available yet." %}</small></p>
</div>
{% elif item.current_unavailability_reason == 'available_from' or var.current_unavailability_reason == 'available_from' %}
<div class="col-md-2 col-sm-3 col-xs-6 availability-box unavailable">
<p><small>{% trans "Not available yet." %}</small></p>

View File

@@ -70,7 +70,7 @@ from pretix.base.models import (
)
from pretix.base.models.event import Event, SubEvent
from pretix.base.models.items import (
ItemAddOn, ItemBundle, SubEventItem, SubEventItemVariation,
Item, ItemAddOn, ItemBundle, SubEventItem, SubEventItemVariation,
)
from pretix.base.services.placeholders import PlaceholderContext
from pretix.base.services.quotas import QuotaAvailability
@@ -302,14 +302,14 @@ def get_grouped_items(event, *, channel: SalesChannel, subevent=None, voucher=No
if item.hidden_if_item_available:
if item.hidden_if_item_available.has_variations:
dependency_available = any(
item._dependency_available = any(
var.check_quotas(subevent=subevent, _cache=quota_cache, include_bundled=True)[0] == Quota.AVAILABILITY_OK
for var in item.hidden_if_item_available.available_variations
)
else:
q = item.hidden_if_item_available.check_quotas(subevent=subevent, _cache=quota_cache, include_bundled=True)
dependency_available = q[0] == Quota.AVAILABILITY_OK
if dependency_available:
item._dependency_available = q[0] == Quota.AVAILABILITY_OK
if item._dependency_available and item.hidden_if_item_available_mode == Item.UNAVAIL_MODE_HIDDEN:
item._remove = True
continue

View File

@@ -38,6 +38,7 @@ var strings = {
'unavailable_available_from': django.pgettext('widget', 'Not yet available'),
'unavailable_available_until': django.pgettext('widget', 'Not available anymore'),
'unavailable_active': django.pgettext('widget', 'Currently not available'),
'unavailable_hidden_if_item_available': django.pgettext('widget', 'Not yet available'),
'order_min': django.pgettext('widget', 'minimum amount to order: %s'),
'exit': django.pgettext('widget', 'Close ticket shop'),
'loading_error': django.pgettext('widget', 'The ticket shop could not be loaded.'),

View File

@@ -323,6 +323,7 @@ TEST_ITEM_RES = {
"max_per_order": None,
"hidden_if_available": None,
"hidden_if_item_available": None,
"hidden_if_item_available_mode": "hide",
"checkin_attention": False,
"checkin_text": None,
"has_variations": False,