Repository: saleor/saleor

Issue:
Problems with creating voucher for category
It seems that changes in the PR #1632 broke something in the voucher form in the dashboard. In the "create voucher" view in the dashboard, after selecting the discount type "A category of products", the category field shows up with an error:

![image](https://user-images.githubusercontent.com/5421321/35149441-592771e8-fd16-11e7-9ff5-1c2caa983c0c.png)

Second, after saving the voucher and going to it's "edit" view, the category is empty which means it wasn't saved in the first step.

Also, I'm unable to apply the newly created voucher in checkout, as it results in the error:

```
AttributeError at /checkout/shipping-address/
'NoneType' object has no attribute 'pk'

Traceback:

File "/Users/marcin/.pyenv/versions/saleor/lib/python3.6/site-packages/django/core/handlers/exception.py" in inner
  41.             response = get_response(request)

File "/Users/marcin/.pyenv/versions/saleor/lib/python3.6/site-packages/django/core/handlers/base.py" in _get_response
  187.                 response = self.process_exception_by_middleware(e, request)

File "/Users/marcin/.pyenv/versions/saleor/lib/python3.6/site-packages/django/core/handlers/base.py" in _get_response
  185.                 response = wrapped_callback(request, *callback_args, **callback_kwargs)

File "/Users/marcin/mirumee/saleor/saleor/cart/utils.py" in func
  207.             return view(request, cart, *args, **kwargs)

File "/Users/marcin/mirumee/saleor/saleor/checkout/core.py" in func
  413.         response = view(request, checkout, cart)

File "/Users/marcin/mirumee/saleor/saleor/checkout/views/discount.py" in func
  65.         return view(request, checkout, cart)

File "/Users/marcin/mirumee/saleor/saleor/checkout/views/validators.py" in func
  20.             return view(request, checkout)

File "/Users/marcin/mirumee/saleor/saleor/checkout/views/validators.py" in func
  72.         return view(request, checkout)

File "/Users/marcin/mirumee/saleor/saleor/checkout/views/discount.py" in func
  24.             if voucher_form.is_valid():

File "/Users/marcin/.pyenv/versions/saleor/lib/python3.6/site-packages/django/forms/forms.py" in is_valid
  183.         return self.is_bound and not self.errors

File "/Users/marcin/.pyenv/versions/saleor/lib/python3.6/site-packages/django/forms/forms.py" in errors
  175.             self.full_clean()

File "/Users/marcin/.pyenv/versions/saleor/lib/python3.6/site-packages/django/forms/forms.py" in full_clean
  385.         self._clean_form()

File "/Users/marcin/.pyenv/versions/saleor/lib/python3.6/site-packages/django/forms/forms.py" in _clean_form
  412.             cleaned_data = self.clean()

File "/Users/marcin/mirumee/saleor/saleor/discount/forms.py" in clean
  44.                 discount = voucher.get_discount_for_checkout(self.checkout)

File "/Users/marcin/mirumee/saleor/saleor/discount/models.py" in get_discount_for_checkout
  178.                         checkout.cart, self.category)))

File "/Users/marcin/mirumee/saleor/saleor/discount/models.py" in <genexpr>
  177.                     (item[1] for item in get_category_variants_and_prices(

File "/Users/marcin/mirumee/saleor/saleor/cart/utils.py" in get_category_variants_and_prices
  80.         if product.category.is_descendant_of(root_category, include_self=True):

File "/Users/marcin/.pyenv/versions/saleor/lib/python3.6/site-packages/mptt/models.py" in _fn
  397.         return func(self, *args, **kwargs)

File "/Users/marcin/.pyenv/versions/saleor/lib/python3.6/site-packages/mptt/models.py" in is_descendant_of
  770.         if include_self and other.pk == self.pk:

Exception Type: AttributeError at /checkout/shipping-address/
Exception Value: 'NoneType' object has no attribute 'pk'
```



Discussion:
Error on voucher's use is result of the category not being saved in database, hence `self.category` being `None` and throwing. This suggests validation isn't tight enough here and lets broken configs through.
Maybe we should make creating vouchers similar to creating products where the voucher type is selected in a separate step and cannot be changed once selected?

Resolving patch:
diff --git a/saleor/dashboard/discount/forms.py b/saleor/dashboard/discount/forms.py
--- a/saleor/dashboard/discount/forms.py
+++ b/saleor/dashboard/discount/forms.py
@@ -160,7 +160,6 @@ def __init__(self, *args, **kwargs):
         super().__init__(*args, **kwargs)
 
     def save(self, commit=True):
-        self.instance.category = None
         self.instance.limit = None
         # Apply to one with percentage discount is more complicated case.
         # On which product we should apply it? On first, last or cheapest?
diff --git a/saleor/dashboard/discount/views.py b/saleor/dashboard/discount/views.py
--- a/saleor/dashboard/discount/views.py
+++ b/saleor/dashboard/discount/views.py
@@ -23,7 +23,7 @@ def get_voucher_type_forms(voucher, data):
         VoucherType.PRODUCT: forms.ProductVoucherForm(
             data or None, instance=voucher, prefix=VoucherType.PRODUCT),
         VoucherType.CATEGORY: forms.CategoryVoucherForm(
-            data, instance=voucher, prefix=VoucherType.CATEGORY)}
+            data or None, instance=voucher, prefix=VoucherType.CATEGORY)}
 
 
 @staff_member_required


Test patch: