Repository: saleor/saleor

Issue:
adding stock to product
Trying out saleor and having some issues setting up the stock on a product.  I suspect that something isn't installed properly or i'm using the wrong version of something.  First I get this error on startup.  The site comes up and I can add products and view cart ect..

```
saleor/.env/local/lib/python2.7/site-packages/model_utils/managers.py:105: RemovedInDjango110Warning: 'get_all_related_objects is an unofficial API that has been deprecated. You may be able to replace it with 'get_fields()'
  rel for rel in model._meta.get_all_related_objects()

/media/storage/home/kirk/projects/saleor/.env/local/lib/python2.7/site-packages/materializecssform/templatetags/materializecss.py:53: RemovedInDjango110Warning: render() must be called with a dict, not a Context.
  return template.render(context)
```

using this url http://127.0.0.1:8000/dashboard/products/1/stock/add/
which calls into 
saleor/saleor/dashboard/product/views.py  

in stock_edit where stock = Stock() is called I get exception

```
  File "/media/storage/home/kirk/projects/saleor/.env/local/lib/python2.7/site-packages/django/db/models/base.py", line 459, in __repr__
    u = six.text_type(self)
  File "/media/storage/home/kirk/projects/saleor/saleor/product/models/base.py", line 272, in __str__
    return '%s - %s' % (self.variant.name, self.location)
  File "/media/storage/home/kirk/projects/saleor/.env/local/lib/python2.7/site-packages/django/db/models/fields/related_descriptors.py", line 179, in __get__
    "%s has no %s." % (self.field.model.__name__, self.field.name)
RelatedObjectDoesNotExist: Stock has no variant.
```

```
product_pk  u'1'
product <saleor.product.models.base.Product(pk=1, name=u'cats')>
request <WSGIRequest: GET '/dashboard/products/1/stock/add/'>
stock_pk    None
stock   Error in formatting: RelatedObjectDoesNotExist: Stock has no variant.
```

After attempting to add stock the page flashes and nothing happens.

```
Babel==2.2.0
BabelDjango==0.2.2
Django==1.9.2
Markdown==2.6.5
Pillow==3.1.1
PyJWT==1.4.0
Unidecode==0.04.19
argparse==1.2.1
boto==2.39.0
braintree==3.24.0
cffi==1.5.0
cryptography==1.2.2
cssselect==0.9.1
cssutils==1.0.1
dj-database-url==0.4.0
dj-email-url==0.0.4
django-absolute==0.3
django-bootstrap3==6.2.2
django-cache-url==1.0.0
django-countries==3.4.1
django-emailit==0.2.2
django-materializecss-form==1.0.1
django-model-utils==2.4
django-mptt==0.8.0
django-offsite-storage==0.0.8
django-payments==0.9.1
django-prices==0.4.11
django-redis==4.3.0
django-selectable==0.9.0
django-versatileimagefield==1.3
djangorestframework==3.3.2
enum34==1.1.2
fake-factory==0.5.3
funcsigs==0.4
google-i18n-address==1.0.7
google-measurement-protocol==0.1.5
idna==2.0
ipaddr==2.1.11
ipaddress==1.0.16
jsonfield==1.0.3
lxml==3.5.0
maxminddb==1.2.0
maxminddb-geolite2==2015.0708
mock==1.3.0
pbr==1.8.1
premailer==2.9.7
prices==0.5.7
psycopg2==2.6.1
purl==1.2
py==1.4.31
pyasn1==0.1.9
pycparser==2.14
pytest==2.8.7
pytest-django==2.9.1
pytz==2015.7
redis==2.10.5
requests==2.9.1
satchless==1.1.3
six==1.10.0
stripe==1.29.1
suds-jurko==0.6
uWSGI==2.0.12
wsgiref==0.1.2
xmltodict==0.9.2

```



Discussion:
Hi,
Which database engine do you use?

sqlite,  using the defaults from config.  no changes.

On Fri, Feb 12, 2016 at 3:09 AM, Artur Smęt notifications@github.com
wrote:

> Hi,
> Which database engine do you use?
> 
> —
> Reply to this email directly or view it on GitHub
> https://github.com/mirumee/saleor/issues/476#issuecomment-183278909.

Getting the same problem, have tried with both SQLite3 and Postgres, default settings

@artursmet @slippers 
1. Open up saleor/dashboard/templates/dashboard/product/stock_form.html
2. Add this line: `{{ form.quantity_allocated|materializecss:"s12 m4 l2" }}` underneath `{{ form.quantity|materializecss:"s12 m4 l2" }}`

quantity_allocated is a required field of the form but isn't there. 
Guessing you guys updated the model without editing the interface.

Thank you.  Maybe they would like a pr?


Resolving patch:
diff --git a/saleor/dashboard/conftest.py b/saleor/dashboard/conftest.py
new file mode 100644
--- /dev/null
+++ b/saleor/dashboard/conftest.py
@@ -0,0 +1,31 @@
+import pytest
+
+@pytest.fixture()
+def admin_user(db, django_user_model, django_username_field):
+    """A Django admin user.
+
+    This uses an existing user with username "admin", or creates a new one with
+    password "password".
+    """
+    UserModel = django_user_model
+    username_field = django_username_field
+
+    try:
+        user = UserModel._default_manager.get(**{username_field: 'admin'})
+    except UserModel.DoesNotExist:
+        extra_fields = {}
+        if username_field not in {'username', 'email'}:
+            extra_fields[username_field] = 'admin'
+        user = UserModel._default_manager.create_superuser(
+            'admin@example.com', 'password', **extra_fields)
+    return user
+
+
+@pytest.fixture()
+def admin_client(db, admin_user):
+    """A Django test client logged in as an admin user."""
+    from django.test.client import Client
+
+    client = Client()
+    client.login(username=admin_user.email, password='password')
+    return client
diff --git a/saleor/dashboard/product/forms.py b/saleor/dashboard/product/forms.py
--- a/saleor/dashboard/product/forms.py
+++ b/saleor/dashboard/product/forms.py
@@ -27,7 +27,7 @@ def __init__(self, *args, **kwargs):
 class StockForm(forms.ModelForm):
     class Meta:
         model = Stock
-        exclude = []
+        exclude = ['quantity_allocated']
 
     def __init__(self, *args, **kwargs):
         product = kwargs.pop('product')
diff --git a/saleor/dashboard/product/views.py b/saleor/dashboard/product/views.py
--- a/saleor/dashboard/product/views.py
+++ b/saleor/dashboard/product/views.py
@@ -1,6 +1,7 @@
 from __future__ import unicode_literals
 
 from django.contrib import messages
+from django.core.urlresolvers import reverse
 from django.shortcuts import get_object_or_404, redirect
 from django.template.response import TemplateResponse
 from django.utils.http import is_safe_url
@@ -91,7 +92,9 @@ def stock_edit(request, product_pk, stock_pk=None):
     if form.is_valid():
         form.save()
         messages.success(request, _('Saved stock'))
-        success_url = request.POST['success_url']
+        product_url = reverse(
+            'dashboard:product-update', kwargs={'pk': product_pk})
+        success_url = request.POST.get('success_url', product_url)
         if is_safe_url(success_url, request.get_host()):
             return redirect(success_url)
     ctx = {'form': form, 'product': product, 'stock': stock}


Test patch:
diff --git a/saleor/dashboard/product/test_product.py b/saleor/dashboard/product/test_product.py
new file mode 100644
--- /dev/null
+++ b/saleor/dashboard/product/test_product.py
@@ -0,0 +1,26 @@
+from __future__ import unicode_literals
+
+from django.core.urlresolvers import reverse
+import pytest
+
+from ...product.test_product import product_in_stock
+
+
+@pytest.mark.integration
+@pytest.mark.django_db
+def test_stock_record_update_works(admin_client, product_in_stock):
+    variant = product_in_stock.variants.get()
+    stock = variant.stock.order_by('-quantity_allocated').first()
+    quantity = stock.quantity
+    quantity_allocated = stock.quantity_allocated
+    url = reverse(
+        'dashboard:product-stock-update', kwargs={
+            'product_pk': product_in_stock.pk,
+            'stock_pk': stock.pk})
+    admin_client.post(url, {
+        'variant': stock.variant_id, 'location': stock.location,
+        'cost_price': stock.cost_price.net,
+        'quantity': quantity + 5})
+    new_stock = variant.stock.get(pk=stock.pk)
+    assert new_stock.quantity == quantity + 5
+    assert new_stock.quantity_allocated == quantity_allocated