Repository: pretix/pretix

Issue:
Handle vouchers with expired items
Hi! When redeeming a voucher for a product where `available_until` is before today, the list for available products is empty and there is no error message.
![image](https://cloud.githubusercontent.com/assets/6865786/25973976/b4a79a5c-36a6-11e7-8d94-9a495951e971.png)
As a user, I would expect
- to buy the ticket regardless of `available_until`, or
- to get an error message

Thanks for your awesome work and with best regards,
Jan Felix


Discussion:
Hi Jan Felix,

good point. I see that alternative (1) could be useful, but giving an error message seems more appropriate as it doesn't come as a (unwelcomed) surprise to organizers. So we should probably give an error message for now.

This should be a non-trivial, but fairly easy fix and I therefore mark this as an easy ticket. If anyone would want to take this on and needs more information, feel free to ask or contact me.

Cheers
Raphael
Hey I want to fix this Can you assign this to me and help me
Hey @captaincrunch21, sure, go ahead, I marked this as assigned. What kind of help do you need? Did you unterstand what this is about or do you have more questions on this? A good start is to get pretix running locally on your computer: https://docs.pretix.eu/en/latest/development/setup.html
Hello, @raphaelm. Can I give this one a try? :)
Hi @chadapohn, let's see if @captaincrunch21 is still working on this?
@chadapohn if you're still interested, I think it would be free…
Hey @raphaelm! I'm a first timer and want to fix the issue. I'm going to read the developer documentation.
Hi @raphaelm, I'm really sorry for seeing this super late. Now I'm reading the developer documentation and trying to run Pretix on my computer.
@chadapohn I guess, you're doing it then!

Hi @sambit-m and @chadapohn, this gets to confusing for me to decide who's doing what now. If one of you wants to look at something else #629 might be fitting

Resolving patch:
diff --git a/src/pretix/base/services/cart.py b/src/pretix/base/services/cart.py
--- a/src/pretix/base/services/cart.py
+++ b/src/pretix/base/services/cart.py
@@ -61,6 +61,8 @@ class CartError(LazyLocaleException):
                         'cart if you want to use it for a different product.'),
     'voucher_expired': _('This voucher is expired.'),
     'voucher_invalid_item': _('This voucher is not valid for this product.'),
+    'voucher_item_not_available': _(
+        'Your voucher is valid for a product that is currently not for sale.'),
     'voucher_invalid_subevent': pgettext_lazy('subevent', 'This voucher is not valid for this event date.'),
     'voucher_required': _('You need a valid voucher code to order this product.'),
     'inactive_subevent': pgettext_lazy('subevent', 'The selected event date is not active.'),
diff --git a/src/pretix/presale/views/cart.py b/src/pretix/presale/views/cart.py
--- a/src/pretix/presale/views/cart.py
+++ b/src/pretix/presale/views/cart.py
@@ -395,6 +395,8 @@ def dispatch(self, request, *args, **kwargs):
                     err = error_messages['voucher_redeemed']
                 if self.voucher.valid_until is not None and self.voucher.valid_until < now():
                     err = error_messages['voucher_expired']
+                if self.voucher.item is not None and self.voucher.item.is_available() is False:
+                    err = error_messages['voucher_item_not_available']
 
                 redeemed_in_carts = CartPosition.objects.filter(
                     Q(voucher=self.voucher) & Q(event=request.event) &


Test patch:
diff --git a/src/tests/presale/test_cart.py b/src/tests/presale/test_cart.py
--- a/src/tests/presale/test_cart.py
+++ b/src/tests/presale/test_cart.py
@@ -15,7 +15,7 @@
 from pretix.base.models.items import (
     ItemAddOn, SubEventItem, SubEventItemVariation,
 )
-from pretix.base.services.cart import CartError, CartManager
+from pretix.base.services.cart import CartError, CartManager, error_messages
 from pretix.testutils.sessions import get_cart_session_key
 
 
@@ -967,6 +967,15 @@ def test_voucher_item_invalid_variation(self):
         objs = list(CartPosition.objects.filter(cart_id=self.session_key, event=self.event))
         self.assertEqual(len(objs), 0)
 
+    def test_voucher_item_not_available_error(self):
+        v = Voucher.objects.create(item=self.ticket, event=self.event)
+        self.ticket.available_until = now() - timedelta(days=2)
+        self.ticket.save()
+        response = self.client.get('/%s/%s/redeem' % (self.orga.slug, self.event.slug),
+                                   {'voucher': v.code},
+                                   follow=True)
+        assert error_messages['voucher_item_not_available'] in response.rendered_content
+
     def test_voucher_price(self):
         v = Voucher.objects.create(item=self.ticket, value=Decimal('12.00'), event=self.event, price_mode='set')
         self.client.post('/%s/%s/cart/add' % (self.orga.slug, self.event.slug), {