forked from CGM_Public/pretix_original
Add program times for items (Z#23178639)
* Add program times for items * Fix frontend date validation * Add ical data for program times [wip] * Improve ical data for program times * Remove duplicate code and add comments * Adjust migration * Remove program times form for event series * Add pdf placeholder [wip] * Improve explanation text with suggestion Co-authored-by: Raphael Michel <michel@pretix.eu> * Fix import sorting * Improve ical generation * Improve ical entry description * Fix migration * Add copyability for program times fot items and events * Update migration * Add API endpoints/functions, fix isort * Improve variable name Co-authored-by: Richard Schreiber <schreiber@rami.io> * Remove todo comment * Add documentation, Change endpoint name * Change related name * Remove unnecessary code block * Add program times to item API * Fix imports * Add log text * Use daterange helper * Add and update API tests * Add another API test * Add program times to cloning tests * Update query count because of program times query * Invalidate cached tickets on program time changes * Reduce invalidation calls * Update migration after rebase * Apply improvements to invalidation from review Co-authored-by: Richard Schreiber <schreiber@rami.io> * remove unneccessary attr=item param * remove unnecessary kwargs for formset_factory * fix local var name being overwritten in for-loop * fix empty formset being saved * Use subevent if available * make code less verbose * remove double event-label in ical desc * fix unnecessary var re-assign * fix ev vs p.subevent --------- Co-authored-by: Raphael Michel <michel@pretix.eu> Co-authored-by: Richard Schreiber <schreiber@rami.io>
This commit is contained in:
25
src/pretix/base/migrations/0294_item_program_time.py
Normal file
25
src/pretix/base/migrations/0294_item_program_time.py
Normal file
@@ -0,0 +1,25 @@
|
||||
# Generated by Django 4.2.19 on 2025-08-11 10:25
|
||||
|
||||
import django.db.models.deletion
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('pretixbase', '0293_cartposition_price_includes_rounding_correction_and_more'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.CreateModel(
|
||||
name='ItemProgramTime',
|
||||
fields=[
|
||||
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False)),
|
||||
('start', models.DateTimeField()),
|
||||
('end', models.DateTimeField()),
|
||||
('item',
|
||||
models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='program_times',
|
||||
to='pretixbase.item')),
|
||||
],
|
||||
),
|
||||
]
|
||||
@@ -36,8 +36,9 @@ from .giftcards import GiftCard, GiftCardAcceptance, GiftCardTransaction
|
||||
from .invoices import Invoice, InvoiceLine, invoice_filename
|
||||
from .items import (
|
||||
Item, ItemAddOn, ItemBundle, ItemCategory, ItemMetaProperty, ItemMetaValue,
|
||||
ItemVariation, ItemVariationMetaValue, Question, QuestionOption, Quota,
|
||||
SubEventItem, SubEventItemVariation, itempicture_upload_to,
|
||||
ItemProgramTime, ItemVariation, ItemVariationMetaValue, Question,
|
||||
QuestionOption, Quota, SubEventItem, SubEventItemVariation,
|
||||
itempicture_upload_to,
|
||||
)
|
||||
from .log import LogEntry
|
||||
from .media import ReusableMedium
|
||||
|
||||
@@ -847,7 +847,7 @@ class Event(EventMixin, LoggedModel):
|
||||
from ..signals import event_copy_data
|
||||
from . import (
|
||||
Discount, Item, ItemAddOn, ItemBundle, ItemCategory, ItemMetaValue,
|
||||
ItemVariationMetaValue, Question, Quota,
|
||||
ItemProgramTime, ItemVariationMetaValue, Question, Quota,
|
||||
)
|
||||
|
||||
# Note: avoid self.set_active_plugins(), it causes trouble e.g. for the badges plugin.
|
||||
@@ -990,6 +990,11 @@ class Event(EventMixin, LoggedModel):
|
||||
ia.bundled_variation = variation_map[ia.bundled_variation.pk]
|
||||
ia.save(force_insert=True)
|
||||
|
||||
for ipt in ItemProgramTime.objects.filter(item__event=other).prefetch_related('item'):
|
||||
ipt.pk = None
|
||||
ipt.item = item_map[ipt.item.pk]
|
||||
ipt.save(force_insert=True)
|
||||
|
||||
quota_map = {}
|
||||
for q in Quota.objects.filter(event=other, subevent__isnull=True).prefetch_related('items', 'variations'):
|
||||
quota_map[q.pk] = q
|
||||
|
||||
@@ -2294,3 +2294,27 @@ class ItemVariationMetaValue(LoggedModel):
|
||||
|
||||
class Meta:
|
||||
unique_together = ('variation', 'property')
|
||||
|
||||
|
||||
class ItemProgramTime(models.Model):
|
||||
"""
|
||||
This model can be used to add a program time to an item.
|
||||
|
||||
:param item: The item the program time applies to
|
||||
:type item: Item
|
||||
:param start: The date and time this program time starts
|
||||
:type start: datetime
|
||||
:param end: The date and time this program time ends
|
||||
:type end: datetime
|
||||
"""
|
||||
item = models.ForeignKey('Item', related_name='program_times', on_delete=models.CASCADE)
|
||||
start = models.DateTimeField(verbose_name=_("Start"))
|
||||
end = models.DateTimeField(verbose_name=_("End"))
|
||||
|
||||
def clean(self):
|
||||
self.clean_start_end(start=self.start, end=self.end)
|
||||
super().clean()
|
||||
|
||||
def clean_start_end(self, start: datetime = None, end: datetime = None):
|
||||
if start and end and start > end:
|
||||
raise ValidationError(_("The program end must not be before the program start."))
|
||||
|
||||
@@ -84,6 +84,7 @@ from pretix.base.settings import PERSON_NAME_SCHEMES
|
||||
from pretix.base.signals import layout_image_variables, layout_text_variables
|
||||
from pretix.base.templatetags.money import money_filter
|
||||
from pretix.base.templatetags.phone_format import phone_format
|
||||
from pretix.helpers.daterange import datetimerange
|
||||
from pretix.helpers.reportlab import ThumbnailingImageReader, reshaper
|
||||
from pretix.presale.style import get_fonts
|
||||
|
||||
@@ -490,6 +491,12 @@ DEFAULT_VARIABLES = OrderedDict((
|
||||
"TIME_FORMAT"
|
||||
) if op.valid_until else ""
|
||||
}),
|
||||
("program_times", {
|
||||
"label": _("Program times: date and time"),
|
||||
"editor_sample": _(
|
||||
"2017-05-31 10:00 – 12:00\n2017-05-31 14:00 – 16:00\n2017-05-31 14:00 – 2017-06-01 14:00"),
|
||||
"evaluate": lambda op, order, ev: get_program_times(op, ev)
|
||||
}),
|
||||
("medium_identifier", {
|
||||
"label": _("Reusable Medium ID"),
|
||||
"editor_sample": "ABC1234DEF4567",
|
||||
@@ -734,6 +741,16 @@ def get_seat(op: OrderPosition):
|
||||
return None
|
||||
|
||||
|
||||
def get_program_times(op: OrderPosition, ev: Event):
|
||||
return '\n'.join([
|
||||
datetimerange(
|
||||
pt.start.astimezone(ev.timezone),
|
||||
pt.end.astimezone(ev.timezone),
|
||||
as_html=False
|
||||
) for pt in op.item.program_times.all()
|
||||
])
|
||||
|
||||
|
||||
def generate_compressed_addon_list(op, order, event):
|
||||
itemcount = defaultdict(int)
|
||||
addons = [p for p in (
|
||||
|
||||
Reference in New Issue
Block a user