forked from CGM_Public/pretix_original
Allow variations to override item meta data (#2965)
This commit is contained in:
@@ -29,7 +29,7 @@ from openpyxl.utils import get_column_letter
|
||||
from ...helpers.safe_openpyxl import SafeCell
|
||||
from ..channels import get_all_sales_channels
|
||||
from ..exporter import ListExporter
|
||||
from ..models import ItemMetaValue
|
||||
from ..models import ItemMetaValue, ItemVariation, ItemVariationMetaValue
|
||||
from ..signals import register_data_exporters
|
||||
|
||||
|
||||
@@ -106,18 +106,27 @@ class ItemDataExporter(ListExporter):
|
||||
yield row
|
||||
|
||||
for i in self.event.items.prefetch_related(
|
||||
'variations',
|
||||
Prefetch(
|
||||
'meta_values',
|
||||
ItemMetaValue.objects.select_related('property'),
|
||||
to_attr='meta_values_cached'
|
||||
)
|
||||
),
|
||||
Prefetch(
|
||||
'variations',
|
||||
queryset=ItemVariation.objects.prefetch_related(
|
||||
Prefetch(
|
||||
'meta_values',
|
||||
ItemVariationMetaValue.objects.select_related('property'),
|
||||
to_attr='meta_values_cached'
|
||||
),
|
||||
),
|
||||
),
|
||||
).select_related('category', 'tax_rule'):
|
||||
m = i.meta_data
|
||||
vars = list(i.variations.all())
|
||||
|
||||
if vars:
|
||||
for v in vars:
|
||||
m = v.meta_data
|
||||
row = [
|
||||
i.pk,
|
||||
v.pk,
|
||||
@@ -160,6 +169,7 @@ class ItemDataExporter(ListExporter):
|
||||
yield row
|
||||
|
||||
else:
|
||||
m = i.meta_data
|
||||
row = [
|
||||
i.pk,
|
||||
"",
|
||||
|
||||
@@ -36,9 +36,11 @@ import json
|
||||
from decimal import Decimal
|
||||
|
||||
from django.core.serializers.json import DjangoJSONEncoder
|
||||
from django.db.models import Prefetch
|
||||
from django.dispatch import receiver
|
||||
|
||||
from ..exporter import BaseExporter
|
||||
from ..models import ItemMetaValue, ItemVariation, ItemVariationMetaValue
|
||||
from ..signals import register_data_exporters
|
||||
|
||||
|
||||
@@ -106,9 +108,26 @@ class JSONExporter(BaseExporter):
|
||||
'available_from': variation.available_from,
|
||||
'available_until': variation.available_until,
|
||||
'hide_without_voucher': variation.hide_without_voucher,
|
||||
'meta_data': variation.meta_data,
|
||||
} for variation in item.variations.all()
|
||||
]
|
||||
} for item in self.event.items.select_related('tax_rule').prefetch_related('variations')
|
||||
} for item in self.event.items.select_related('tax_rule').prefetch_related(
|
||||
Prefetch(
|
||||
'meta_values',
|
||||
ItemMetaValue.objects.select_related('property'),
|
||||
to_attr='meta_values_cached'
|
||||
),
|
||||
Prefetch(
|
||||
'variations',
|
||||
queryset=ItemVariation.objects.prefetch_related(
|
||||
Prefetch(
|
||||
'meta_values',
|
||||
ItemVariationMetaValue.objects.select_related('property'),
|
||||
to_attr='meta_values_cached'
|
||||
),
|
||||
),
|
||||
),
|
||||
)
|
||||
],
|
||||
'questions': [
|
||||
{
|
||||
|
||||
29
src/pretix/base/migrations/0226_itemvariationmetavalue.py
Normal file
29
src/pretix/base/migrations/0226_itemvariationmetavalue.py
Normal file
@@ -0,0 +1,29 @@
|
||||
# Generated by Django 3.2.16 on 2022-12-09 10:06
|
||||
|
||||
import django.db.models.deletion
|
||||
from django.db import migrations, models
|
||||
|
||||
import pretix.base.models.base
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('pretixbase', '0225_orderpayment_process_initiated'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.CreateModel(
|
||||
name='ItemVariationMetaValue',
|
||||
fields=[
|
||||
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False)),
|
||||
('value', models.TextField()),
|
||||
('property', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='variation_values', to='pretixbase.itemmetaproperty')),
|
||||
('variation', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='meta_values', to='pretixbase.itemvariation')),
|
||||
],
|
||||
options={
|
||||
'unique_together': {('variation', 'property')},
|
||||
},
|
||||
bases=(models.Model, pretix.base.models.base.LoggingMixin),
|
||||
),
|
||||
]
|
||||
@@ -34,8 +34,8 @@ from .giftcards import GiftCard, GiftCardAcceptance, GiftCardTransaction
|
||||
from .invoices import Invoice, InvoiceLine, invoice_filename
|
||||
from .items import (
|
||||
Item, ItemAddOn, ItemBundle, ItemCategory, ItemMetaProperty, ItemMetaValue,
|
||||
ItemVariation, Question, QuestionOption, Quota, SubEventItem,
|
||||
SubEventItemVariation, itempicture_upload_to,
|
||||
ItemVariation, ItemVariationMetaValue, Question, QuestionOption, Quota,
|
||||
SubEventItem, SubEventItemVariation, itempicture_upload_to,
|
||||
)
|
||||
from .log import LogEntry
|
||||
from .memberships import Membership, MembershipType
|
||||
|
||||
@@ -728,7 +728,7 @@ class Event(EventMixin, LoggedModel):
|
||||
from ..signals import event_copy_data
|
||||
from . import (
|
||||
Discount, Item, ItemAddOn, ItemBundle, ItemCategory, ItemMetaValue,
|
||||
Question, Quota,
|
||||
ItemVariationMetaValue, Question, Quota,
|
||||
)
|
||||
|
||||
# Note: avoid self.set_active_plugins(), it causes trouble e.g. for the badges plugin.
|
||||
@@ -804,12 +804,18 @@ class Event(EventMixin, LoggedModel):
|
||||
v.item = i
|
||||
v.save(force_insert=True)
|
||||
|
||||
for imv in ItemMetaValue.objects.filter(item__event=other).prefetch_related('item', 'property'):
|
||||
for imv in ItemMetaValue.objects.filter(item__event=other):
|
||||
imv.pk = None
|
||||
imv.property = item_meta_properties_map[imv.property.pk]
|
||||
imv.property = item_meta_properties_map[imv.property_id]
|
||||
imv.item = item_map[imv.item.pk]
|
||||
imv.save(force_insert=True)
|
||||
|
||||
for imv in ItemVariationMetaValue.objects.filter(variation__item__event=other):
|
||||
imv.pk = None
|
||||
imv.property = item_meta_properties_map[imv.property_id]
|
||||
imv.variation = variation_map[imv.variation_id]
|
||||
imv.save(force_insert=True)
|
||||
|
||||
for ia in ItemAddOn.objects.filter(base_item__event=other).prefetch_related('base_item', 'addon_category'):
|
||||
ia.pk = None
|
||||
ia.base_item = item_map[ia.base_item.pk]
|
||||
|
||||
@@ -1008,6 +1008,16 @@ class ItemVariation(models.Model):
|
||||
return False
|
||||
return True
|
||||
|
||||
@property
|
||||
def meta_data(self):
|
||||
data = self.item.meta_data
|
||||
if hasattr(self, 'meta_values_cached'):
|
||||
data.update({v.property.name: v.value for v in self.meta_values_cached})
|
||||
else:
|
||||
data.update({v.property.name: v.value for v in self.meta_values.select_related('property').all()})
|
||||
|
||||
return OrderedDict((k, v) for k, v in sorted(data.items(), key=lambda k: k[0]))
|
||||
|
||||
|
||||
class ItemAddOn(models.Model):
|
||||
"""
|
||||
@@ -1787,8 +1797,21 @@ class ItemMetaValue(LoggedModel):
|
||||
class Meta:
|
||||
unique_together = ('item', 'property')
|
||||
|
||||
def delete(self, *args, **kwargs):
|
||||
super().delete(*args, **kwargs)
|
||||
|
||||
def save(self, *args, **kwargs):
|
||||
super().save(*args, **kwargs)
|
||||
class ItemVariationMetaValue(LoggedModel):
|
||||
"""
|
||||
A meta-data value assigned to an item variation, overriding the value on the item.
|
||||
|
||||
:param variation: The variation this metadata is valid for
|
||||
:type variation: ItemVariation
|
||||
:param property: The property this value belongs to
|
||||
:type property: ItemMetaProperty
|
||||
:param value: The actual value
|
||||
:type value: str
|
||||
"""
|
||||
variation = models.ForeignKey('ItemVariation', on_delete=models.CASCADE, related_name='meta_values')
|
||||
property = models.ForeignKey('ItemMetaProperty', on_delete=models.CASCADE, related_name='variation_values')
|
||||
value = models.TextField()
|
||||
|
||||
class Meta:
|
||||
unique_together = ('variation', 'property')
|
||||
|
||||
@@ -746,6 +746,8 @@ class Renderer:
|
||||
|
||||
def replace(x):
|
||||
if x.group(1).startswith('itemmeta:'):
|
||||
if op.variation_id:
|
||||
return op.variation.meta_data.get(x.group(1)[9:]) or ''
|
||||
return op.item.meta_data.get(x.group(1)[9:]) or ''
|
||||
elif x.group(1).startswith('meta:'):
|
||||
return ev.meta_data.get(x.group(1)[5:]) or ''
|
||||
@@ -766,6 +768,8 @@ class Renderer:
|
||||
return re.sub(r'\{([a-zA-Z0-9:_]+)\}', replace, text)
|
||||
|
||||
elif o['content'].startswith('itemmeta:'):
|
||||
if op.variation_id:
|
||||
return op.variation.meta_data.get(o['content'][9:]) or ''
|
||||
return op.item.meta_data.get(o['content'][9:]) or ''
|
||||
|
||||
elif o['content'].startswith('meta:'):
|
||||
|
||||
Reference in New Issue
Block a user