Fix #91 -- Make products/orders that are not cancelable (#204)

* Make products/orders that are not cancellable
Update Unit Tests

* Make use of select_related instead of prefetch_related
Simplify cancellable logic
Migrations

* Simplify cancellable logic
Maske use of select_related instead of prefetch_related

* Fix cancelable condition bug
This commit is contained in:
Enrique Saez
2016-09-01 08:55:02 +02:00
committed by Raphael Michel
parent 022e02d913
commit 841cfe52a2
8 changed files with 114 additions and 1 deletions

View File

@@ -0,0 +1,20 @@
# -*- coding: utf-8 -*-
# Generated by Django 1.9.9 on 2016-08-22 10:23
from __future__ import unicode_literals
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('pretixbase', '0031_auto_20160816_0648'),
]
operations = [
migrations.AddField(
model_name='item',
name='allow_cancel',
field=models.BooleanField(default=True, help_text='Whether this product might or not be cancelled.', verbose_name='Allow a product to be cancelled'),
),
]

View File

@@ -0,0 +1,20 @@
# -*- coding: utf-8 -*-
# Generated by Django 1.9.9 on 2016-08-22 10:44
from __future__ import unicode_literals
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('pretixbase', '0032_item_allow_cancel'),
]
operations = [
migrations.AlterField(
model_name='item',
name='allow_cancel',
field=models.BooleanField(default=True, help_text='Whether this product might or not be cancelled.', verbose_name='Allow product to be cancelled'),
),
]

View File

@@ -0,0 +1,16 @@
# -*- coding: utf-8 -*-
# Generated by Django 1.9.9 on 2016-08-31 21:04
from __future__ import unicode_literals
from django.db import migrations
class Migration(migrations.Migration):
dependencies = [
('pretixbase', '0033_auto_20160822_1044'),
('pretixbase', '0034_auto_20160830_1952'),
]
operations = [
]

View File

@@ -186,6 +186,11 @@ class Item(LoggedModel):
help_text=_('This product will be hidden from the event page until the user enters a voucher ' help_text=_('This product will be hidden from the event page until the user enters a voucher '
'code that is specifically tied to this product (and not via a quota).') 'code that is specifically tied to this product (and not via a quota).')
) )
allow_cancel = models.BooleanField(
verbose_name=_('Allow product to be cancelled'),
default=True,
help_text=_('Whether this product might or not be cancelled.')
)
class Meta: class Meta:
verbose_name = _("Product") verbose_name = _("Product")

View File

@@ -243,7 +243,9 @@ class Order(LoggedModel):
@property @property
def can_user_cancel(self) -> bool: def can_user_cancel(self) -> bool:
return self.event.settings.cancel_allow_user positions = self.positions.all().select_related('item')
cancelable = all([op.item.allow_cancel for op in positions])
return self.event.settings.cancel_allow_user and cancelable
@property @property
def is_expired_by_time(self): def is_expired_by_time(self):

View File

@@ -119,6 +119,7 @@ class ItemCreateForm(I18nModelForm):
'admission', 'admission',
'default_price', 'default_price',
'tax_rate', 'tax_rate',
'allow_cancel'
] ]
@@ -144,6 +145,7 @@ class ItemUpdateForm(I18nModelForm):
'available_until', 'available_until',
'require_voucher', 'require_voucher',
'hide_without_voucher', 'hide_without_voucher',
'allow_cancel'
] ]

View File

@@ -25,6 +25,7 @@
{% bootstrap_field form.available_until layout="horizontal" %} {% bootstrap_field form.available_until layout="horizontal" %}
{% bootstrap_field form.require_voucher layout="horizontal" %} {% bootstrap_field form.require_voucher layout="horizontal" %}
{% bootstrap_field form.hide_without_voucher layout="horizontal" %} {% bootstrap_field form.hide_without_voucher layout="horizontal" %}
{% bootstrap_field form.allow_cancel layout="horizontal" %}
</fieldset> </fieldset>
<div class="form-group submit-group"> <div class="form-group submit-group">
<button type="submit" class="btn btn-primary btn-save"> <button type="submit" class="btn btn-primary btn-save">

View File

@@ -393,6 +393,53 @@ class OrderTestCase(BaseQuotaTestCase):
self.event.settings.set('last_order_modification_date', now() - timedelta(days=1)) self.event.settings.set('last_order_modification_date', now() - timedelta(days=1))
assert not self.order.can_modify_answers assert not self.order.can_modify_answers
def test_can_cancel_order(self):
item1 = Item.objects.create(event=self.event, name="Ticket", default_price=23,
admission=True, allow_cancel=True)
OrderPosition.objects.create(order=self.order, item=item1,
variation=None, price=23)
assert self.order.can_user_cancel
def test_can_cancel_order_multiple(self):
item1 = Item.objects.create(event=self.event, name="Ticket", default_price=23,
admission=True, allow_cancel=True)
item2 = Item.objects.create(event=self.event, name="Ticket", default_price=23,
admission=True, allow_cancel=True)
OrderPosition.objects.create(order=self.order, item=item1,
variation=None, price=23)
OrderPosition.objects.create(order=self.order, item=item2,
variation=None, price=23)
assert self.order.can_user_cancel
def test_can_not_cancel_order(self):
item1 = Item.objects.create(event=self.event, name="Ticket", default_price=23,
admission=True, allow_cancel=False)
OrderPosition.objects.create(order=self.order, item=item1,
variation=None, price=23)
assert self.order.can_user_cancel is False
def test_can_not_cancel_order_multiple(self):
item1 = Item.objects.create(event=self.event, name="Ticket", default_price=23,
admission=True, allow_cancel=False)
item2 = Item.objects.create(event=self.event, name="Ticket", default_price=23,
admission=True, allow_cancel=True)
OrderPosition.objects.create(order=self.order, item=item1,
variation=None, price=23)
OrderPosition.objects.create(order=self.order, item=item2,
variation=None, price=23)
assert self.order.can_user_cancel is False
def test_can_not_cancel_order_multiple_mixed(self):
item1 = Item.objects.create(event=self.event, name="Ticket", default_price=23,
admission=True, allow_cancel=False)
item2 = Item.objects.create(event=self.event, name="Ticket", default_price=23,
admission=True, allow_cancel=True)
OrderPosition.objects.create(order=self.order, item=item1,
variation=None, price=23)
OrderPosition.objects.create(order=self.order, item=item2,
variation=None, price=23)
assert self.order.can_user_cancel is False
class ItemCategoryTest(TestCase): class ItemCategoryTest(TestCase):
""" """