Add sales channels (#1103)

- [x] Data model
- [x] Enforce constraint
- [x] Filter order list
- [x] Set channel on created order
- [x] Products API
- [x] Order API
- [x] Tests
- [x] Filter reports
- [x] Resellers
- [ ] deploy plugins
  - [ ] posbackend
  - [ ] resellers
  - [ ] reports
- [x] Ticketlayouts
- [x] Support in pretixPOS
This commit is contained in:
Raphael Michel
2018-11-23 15:35:09 +01:00
committed by GitHub
parent 0f76779fb1
commit b4290384e1
39 changed files with 472 additions and 57 deletions

View File

@@ -10,7 +10,7 @@ class ItemAssignmentSerializer(I18nAwareModelSerializer):
class Meta:
model = TicketLayoutItem
fields = ('item',)
fields = ('item', 'sales_channel')
class TicketLayoutSerializer(I18nAwareModelSerializer):

View File

@@ -85,7 +85,13 @@ class AllTicketsPDF(BaseExporter):
with language(op.order.locale):
buffer = BytesIO()
p = o._create_canvas(buffer)
layout = o.layout_map.get(op.item_id, o.default_layout)
layout = o.layout_map.get(
(op.item_id, op.order.sales_channel),
o.layout_map.get(
(op.item_id, 'web'),
o.default_layout
)
)
o._draw_page(layout, p, op, op.order)
p.save()
outbuffer = o._render_with_background(layout, buffer)

View File

@@ -19,13 +19,21 @@ class TicketLayoutItemForm(forms.ModelForm):
def __init__(self, *args, **kwargs):
event = kwargs.pop('event')
self.sales_channel = kwargs.pop('sales_channel')
super().__init__(*args, **kwargs)
self.fields['layout'].label = _('PDF ticket layout')
self.fields['layout'].empty_label = _('(Event default)')
if self.sales_channel.identifier != 'web':
self.fields['layout'].label = _('PDF ticket layout for {channel}').format(
channel=self.sales_channel.verbose_name
)
self.fields['layout'].empty_label = _('(Same as above)')
else:
self.fields['layout'].label = _('PDF ticket layout')
self.fields['layout'].empty_label = _('(Event default)')
self.fields['layout'].queryset = event.ticket_layouts.all()
self.fields['layout'].required = False
def save(self, commit=True):
self.instance.sales_channel = self.sales_channel.identifier
if self.cleaned_data['layout'] is None:
if self.instance.pk:
self.instance.delete()

View File

@@ -0,0 +1,29 @@
# Generated by Django 2.1.1 on 2018-11-23 10:59
import django.db.models.deletion
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('pretixbase', '0103_auto_20181121_1224'),
('ticketoutputpdf', '0006_auto_20181017_0024'),
]
operations = [
migrations.AddField(
model_name='ticketlayoutitem',
name='sales_channel',
field=models.CharField(default='web', max_length=190),
),
migrations.AlterField(
model_name='ticketlayoutitem',
name='item',
field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='ticketlayout_assignments', to='pretixbase.Item'),
),
migrations.AlterUniqueTogether(
name='ticketlayoutitem',
unique_together={('item', 'layout', 'sales_channel')},
),
]

View File

@@ -66,6 +66,10 @@ class TicketLayout(LoggedModel):
class TicketLayoutItem(models.Model):
item = models.OneToOneField('pretixbase.Item', null=True, blank=True, related_name='ticketlayout_assignment',
on_delete=models.CASCADE)
item = models.ForeignKey('pretixbase.Item', null=True, blank=True, related_name='ticketlayout_assignments',
on_delete=models.CASCADE)
layout = models.ForeignKey('TicketLayout', on_delete=models.CASCADE, related_name='item_assignments')
sales_channel = models.CharField(max_length=190, default='web')
class Meta:
unique_together = (('item', 'layout', 'sales_channel'),)

View File

@@ -7,6 +7,7 @@ from django.urls import reverse
from django.utils.html import escape
from django.utils.translation import ugettext_lazy as _
from pretix.base.channels import get_all_sales_channels
from pretix.base.models import QuestionAnswer
from pretix.base.signals import ( # NOQA: legacy import
event_copy_data, item_copy_data, layout_text_variables, logentry_display,
@@ -61,25 +62,26 @@ def variables_from_questions(sender, *args, **kwargs):
@receiver(item_forms, dispatch_uid="pretix_ticketoutputpdf_item_forms")
def control_item_forms(sender, request, item, **kwargs):
try:
inst = TicketLayoutItem.objects.get(item=item)
except TicketLayoutItem.DoesNotExist:
inst = TicketLayoutItem(item=item)
return TicketLayoutItemForm(
instance=inst,
event=sender,
data=(request.POST if request.method == "POST" else None),
prefix="ticketlayoutitem"
)
forms = []
for k, v in sorted(list(get_all_sales_channels().items()), key=lambda a: (int(a[0] != 'web'), a[0])):
try:
inst = TicketLayoutItem.objects.get(item=item, sales_channel=k)
except TicketLayoutItem.DoesNotExist:
inst = TicketLayoutItem(item=item)
forms.append(TicketLayoutItemForm(
instance=inst,
event=sender,
sales_channel=v,
data=(request.POST if request.method == "POST" else None),
prefix="ticketlayoutitem_{}".format(k)
))
return forms
@receiver(item_copy_data, dispatch_uid="pretix_ticketoutputpdf_item_copy")
def copy_item(sender, source, target, **kwargs):
try:
inst = TicketLayoutItem.objects.get(item=source)
TicketLayoutItem.objects.create(item=target, layout=inst.layout)
except TicketLayoutItem.DoesNotExist:
pass
for tli in TicketLayoutItem.objects.filter(item=source):
TicketLayoutItem.objects.create(item=target, layout=tli.layout, sales_channel=tli.sales_channel)
@receiver(signal=event_copy_data, dispatch_uid="pretix_ticketoutputpdf_copy_data")
@@ -110,7 +112,8 @@ def pdf_event_copy_data_receiver(sender, other, item_map, question_map, **kwargs
layout_map[oldid] = bl
for bi in TicketLayoutItem.objects.filter(item__event=other):
TicketLayoutItem.objects.create(item=item_map.get(bi.item_id), layout=layout_map.get(bi.layout_id))
TicketLayoutItem.objects.create(item=item_map.get(bi.item_id), layout=layout_map.get(bi.layout_id),
sales_channel=bi.sales_channel)
return layout_map

View File

@@ -37,7 +37,7 @@ class PdfTicketOutput(BaseTicketOutput):
@cached_property
def layout_map(self):
return {
bi.item_id: bi.layout
(bi.item_id, bi.sales_channel): bi.layout
for bi in TicketLayoutItem.objects.select_related('layout').filter(item__event=self.event)
}
@@ -68,7 +68,13 @@ class PdfTicketOutput(BaseTicketOutput):
buffer = BytesIO()
p = self._create_canvas(buffer)
layout = self.layout_map.get(op.item_id, self.default_layout)
layout = self.layout_map.get(
(op.item_id, order.sales_channel),
self.layout_map.get(
(op.item_id, 'web'),
self.default_layout
)
)
self._draw_page(layout, p, op, order)
p.save()
outbuffer = self._render_with_background(layout, buffer)
@@ -84,7 +90,13 @@ class PdfTicketOutput(BaseTicketOutput):
buffer = BytesIO()
p = self._create_canvas(buffer)
order = op.order
layout = self.layout_map.get(op.item_id, self.default_layout)
layout = self.layout_map.get(
(op.item_id, order.sales_channel),
self.layout_map.get(
(op.item_id, 'web'),
self.default_layout
)
)
with language(order.locale):
self._draw_page(layout, p, op, order)
p.save()