We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
Show if inventory item is available in nibble shop in product listing
## What kind of an issue is this?

- [x] Feature request


## What is the expected behaviour?

There should be an icon in the dashboard product listing page that shows if an item is available for sale in Nibble.

This icon should also be clickable, to toggle whether or not the item should be available for sale in Nibble.

It should be possible to sort the items in the table according to the "available for sale"-state.


## Other information

This is how an event's attendee list looks, and it could probably be done in the same way (look at the rightmost column): 
![screenshot 2017-02-27 17 05 03](https://cloud.githubusercontent.com/assets/5422571/23368846/7f1a2600-fd0f-11e6-9499-7afeedf65f76.png)

This is to be done in this list:
![screenshot 2017-02-27 17 05 47](https://cloud.githubusercontent.com/assets/5422571/23368830/72016b18-fd0f-11e6-98f0-485ccebe14c7.png)


--- END ISSUE ---

Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
--- BEGIN FILES ---
Path: `apps/inventory/dashboard/urls.py`
Content:
```
1 # -*- encoding: utf-8 -*-
2 
3 from django.conf.urls import url
4 
5 from apps.inventory.dashboard import views
6 
7 urlpatterns = [
8     url(r'^$', views.index, name='dashboard_inventory_index'),
9     url(r'^statistics/$', views.statistics, name='dashboard_inventory_statistics'),
10     url(r'^statistics/orders/$', views.order_statistics, name='dashboard_inventory_order_statistics'),
11 
12     url(r'^category/$', views.category_index, name='dashboard_category_index'),
13     url(r'^category/(?P<category_pk>\d+)/$', views.category_details, name='dashboard_category_details'),
14     url(r'^category/new/$', views.category_new, name='dashboard_category_new'),
15     url(r'^category/(?P<category_pk>\d+)/delete/$', views.category_delete, name='dashboard_category_delete'),
16 
17     url(r'^new/$', views.new, name='dashboard_inventory_new'),
18     url(r'^item/(?P<item_pk>\d+)/$', views.details, name='dashboard_inventory_details'),
19     url(r'^item/(?P<item_pk>\d+)/delete/$', views.item_delete, name='dashboard_inventory_delete'),
20     url(r'^item/(?P<item_pk>\d+)/batch/new/$', views.batch_new, name='dashboard_inventory_batch_new'),
21     url(r'^item/(?P<item_pk>\d+)/batch/(?P<batch_pk>\d+)/$', views.batch, name='dashboard_inventory_batch'),
22     url(r'^item/(?P<item_pk>\d+)/batch/(?P<batch_pk>\d+)/delete/$',
23         views.batch_delete,
24         name='dashboard_inventory_batch_delete'),
25 ]
26
```

Path: `apps/inventory/dashboard/views.py`
Content:
```
1 # -*- encoding: utf-8 -*-
2 
3 from logging import getLogger
4 
5 from django.contrib import messages
6 from django.contrib.auth.decorators import login_required
7 from django.contrib.contenttypes.models import ContentType
8 from django.core.exceptions import PermissionDenied
9 from django.db.models import Count
10 from django.http import JsonResponse
11 from django.shortcuts import get_object_or_404, redirect, render
12 from guardian.decorators import permission_required
13 
14 from apps.dashboard.tools import get_base_context, has_access
15 from apps.inventory.dashboard.forms import BatchForm, CategoryForm, ItemForm
16 from apps.inventory.models import Batch, Item, ItemCategory
17 from apps.shop.models import Order
18 
19 
20 @login_required
21 @permission_required('inventory.view_item', return_403=True)
22 def index(request):
23 
24     # Generic check to see if user has access to dashboard. (In Komiteer or superuser)
25     if not has_access(request):
26         raise PermissionDenied
27 
28     # Create the base context needed for the sidebar
29     context = get_base_context(request)
30 
31     context['items'] = Item.objects.all().order_by('name')
32 
33     return render(request, 'inventory/dashboard/index.html', context)
34 
35 
36 @login_required
37 @permission_required('inventory.add_item', return_403=True)
38 def new(request):
39 
40     if not has_access(request):
41         raise PermissionDenied
42 
43     # Get base context
44     context = get_base_context(request)
45 
46     if request.method == 'POST':
47         inventory_form = ItemForm(request.POST)
48 
49         if not inventory_form.is_valid():
50             messages.error(request, 'Noen av de påkrevde feltene inneholder feil.')
51         else:
52             item = inventory_form.save()
53             messages.success(request, 'Varen ble opprettet')
54             return redirect(details, item.id)
55 
56         context['form'] = inventory_form
57 
58     else:
59         context['form'] = ItemForm()
60 
61     return render(request, 'inventory/dashboard/new.html', context)
62 
63 
64 @login_required
65 @permission_required('inventory.view_item', return_403=True)
66 def details(request, item_pk):
67     # Generic check to see if user has access to dashboard. (In Komiteer or superuser)
68     if not has_access(request):
69         raise PermissionDenied
70 
71     # Create the base context needed for the sidebar
72     context = get_base_context(request)
73 
74     context['item'] = get_object_or_404(Item, pk=item_pk)
75 
76     if request.method == 'POST':
77         if 'inventory.change_item' not in context['user_permissions']:
78             raise PermissionDenied
79 
80         item_form = ItemForm(request.POST, instance=context['item'])
81         if not item_form.is_valid():
82             messages.error(request, 'Noen av de påkrevde feltene inneholder feil.')
83         else:
84             item_form.save()
85             messages.success(request, 'Varen ble oppdatert')
86         context['form'] = item_form
87     else:
88         context['form'] = ItemForm(instance=context['item'])
89 
90     context['new_batch_form'] = BatchForm()
91 
92     context['batch_forms'] = [
93         (b.id, BatchForm(instance=b)) for b in Batch.objects.filter(item=context['item'])
94     ]
95 
96     return render(request, 'inventory/dashboard/details.html', context)
97 
98 
99 @login_required
100 @permission_required('inventory.delete_item', return_403=True)
101 def item_delete(request, item_pk):
102     if not has_access(request):
103         raise PermissionDenied
104 
105     item = get_object_or_404(Item, pk=item_pk)
106 
107     if request.method == 'POST':
108 
109         item.delete()
110 
111         messages.success(request, 'Varen %s ble slettet.' % item.name)
112 
113         return redirect(index)
114 
115     raise PermissionDenied
116 
117 
118 @login_required
119 @permission_required('inventory.add_batch', return_403=True)
120 def batch_new(request, item_pk):
121     if not has_access(request):
122         raise PermissionDenied
123 
124     # Field mapper
125     fieldmap = {
126         'amount': 'Mengde',
127         'expiration_date': 'Utløpsdato',
128     }
129 
130     item = get_object_or_404(Item, pk=item_pk)
131 
132     if request.method == 'POST':
133         batch_form = BatchForm(request.POST)
134 
135         if not batch_form.is_valid():
136             # Dirty hack to display errors since the form is not passed in redirect context
137             error_reply = "Feil i felt:"
138             for field, error in batch_form.errors.items():
139                 error_reply += ' ' + fieldmap[field] + ' (' + batch_form.error_class.as_text(error) + '),'
140 
141             messages.error(request, error_reply.rstrip(','))
142         else:
143             b = batch_form.save(commit=False)
144             b.item = item
145             b.save()
146             messages.success(request, 'Batchen ble lagt til.')
147 
148         return redirect(details, item_pk=item_pk)
149 
150     raise PermissionDenied
151 
152 
153 @login_required
154 @permission_required('inventory.change_batch', return_403=True)
155 def batch(request, item_pk, batch_pk):
156     if not has_access(request):
157         raise PermissionDenied
158 
159     # Get base context
160 
161     get_object_or_404(Item, pk=item_pk)
162     b = get_object_or_404(Batch, pk=batch_pk)
163 
164     if request.method == 'POST':
165         batch_form = BatchForm(request.POST, instance=b)
166 
167         if not batch_form.is_valid():
168             messages.error(request, 'Noen av de påkrevde feltene inneholder feil.')
169         else:
170             batch_form.save()
171             messages.success(request, 'Batchen ble oppdatert.')
172 
173         return redirect(details, item_pk=item_pk)
174 
175     raise PermissionDenied
176 
177 
178 @login_required
179 @permission_required('inventory.delete_batch', return_403=True)
180 def batch_delete(request, item_pk, batch_pk):
181     if not has_access(request):
182         raise PermissionDenied
183 
184     b = get_object_or_404(Batch, pk=batch_pk)
185 
186     if request.method == 'POST':
187 
188         b.delete()
189         messages.success(request, 'Batchen ble slettet.')
190 
191         return redirect(details, item_pk=item_pk)
192 
193     raise PermissionDenied
194 
195 
196 @login_required
197 @permission_required('inventory.view_itemcategory', return_403=True)
198 def category_index(request):
199 
200     # Generic check to see if user has access to dashboard. (In Komiteer or superuser)
201     if not has_access(request):
202         raise PermissionDenied
203 
204     # Create the base context needed for the sidebar
205     context = get_base_context(request)
206 
207     context['categories'] = ItemCategory.objects.all()
208 
209     return render(request, 'inventory/dashboard/category_index.html', context)
210 
211 
212 @login_required
213 @permission_required('inventory.view_itemcategory', return_403=True)
214 def category_details(request, category_pk):
215     # Generic check to see if user has access to dashboard. (In Komiteer or superuser)
216     if not has_access(request):
217         raise PermissionDenied
218 
219     # Create the base context needed for the sidebar
220     context = get_base_context(request)
221 
222     context['category'] = get_object_or_404(ItemCategory, pk=category_pk)
223 
224     if request.method == 'POST':
225 
226         form = CategoryForm(request.POST, instance=context['category'])
227         if not form.is_valid():
228             messages.error(request, 'Noen av de påkrevde feltene inneholder feil.')
229         else:
230             form.save()
231             messages.success(request, 'Kategorien ble oppdatert')
232             return redirect(category_index)
233 
234         context['form'] = form
235     else:
236         context['form'] = CategoryForm(instance=context['category'])
237 
238     return render(request, 'inventory/dashboard/category_new.html', context)
239 
240 
241 @login_required
242 @permission_required('inventory.add_itemcategory', return_403=True)
243 def category_new(request):
244 
245     if not has_access(request):
246         raise PermissionDenied
247 
248     # Get base context
249     context = get_base_context(request)
250 
251     if request.method == 'POST':
252         form = CategoryForm(request.POST)
253 
254         if not form.is_valid():
255             messages.error(request, 'Noen av de påkrevde feltene inneholder feil.')
256         else:
257             form.save()
258             messages.success(request, 'Kategorien ble opprettet')
259             return redirect(category_index)
260 
261         context['form'] = form
262     else:
263         context['form'] = CategoryForm()
264 
265     return render(request, 'inventory/dashboard/category_new.html', context)
266 
267 
268 @login_required
269 @permission_required('inventory.delete_itemcategory', return_403=True)
270 def category_delete(request, category_pk):
271     if not has_access(request):
272         raise PermissionDenied
273 
274     category = get_object_or_404(ItemCategory, pk=category_pk)
275 
276     items = Item.objects.filter(category=category)
277 
278     # Removes the category binding to prevent cascading delete
279     for item in items:
280         item.category = None
281         item.save()
282 
283     category.delete()
284     messages.success(request, 'Kategorien %s ble slettet.' % category.name)
285     return redirect(category_index)
286 
287     raise PermissionDenied
288 
289 
290 @login_required
291 # @permission_required('inventory.delete_batch', return_403=True)
292 def statistics(request):
293     # if not has_access(request):
294     #     raise PermissionDenied
295 
296     context = get_base_context(request)
297 
298     return render(request, 'inventory/dashboard/statistics.html', context)
299 
300 
301 @login_required
302 def order_statistics(request):
303     # TODO check permissions
304 
305     statistics = dict()
306 
307     counts = Order.objects.all().values('object_id', 'content_type').annotate(total=Count('object_id'))
308     item_type = ContentType.objects.get_for_model(Item)
309 
310     for count in counts:
311         print(count)
312         if item_type.id == count['content_type']:
313             try:
314                 item = Item.objects.get(pk=count['object_id'])
315             except Item.DoesNotExist:
316                 getLogger(__name__).error('Item with pk %s does not exist (DoesNotExist error)' % count['object_id'])
317             except KeyError:
318                 getLogger(__name__).error('Key "object_id" does not exist')
319             if count['total'] > 0:
320                 statistics[item.name] = count['total']
321 
322     return JsonResponse(statistics)
323
```
--- END FILES ---

Please first localize the bug based on the issue statement, and then generate a patch according to the `git diff` format fenced by three backticks.

Here is an example:

```diff
diff --git a/examples/server_async.py b/examples/server_async.py
--- a/examples/server_async.py
+++ b/examples/server_async.py
@@ -313,4 +313,4 @@
 
 
 if __name__ == "__main__":
-    asyncio.run(run_async_server("."), debug=True)
+    asyncio.run(run_async_server(), debug=True)
diff --git a/examples/server_sync.py b/examples/server_sync.py
--- a/examples/server_sync.py
+++ b/examples/server_sync.py
@@ -313,5 +313,5 @@
 
 
 if __name__ == "__main__":
-    server = run_sync_server(".")
+    server = run_sync_server()
     server.shutdown()

```

diff --git a/apps/inventory/dashboard/urls.py b/apps/inventory/dashboard/urls.py
--- a/apps/inventory/dashboard/urls.py
+++ b/apps/inventory/dashboard/urls.py
@@ -17,6 +17,7 @@
     url(r'^new/$', views.new, name='dashboard_inventory_new'),
     url(r'^item/(?P<item_pk>\d+)/$', views.details, name='dashboard_inventory_details'),
     url(r'^item/(?P<item_pk>\d+)/delete/$', views.item_delete, name='dashboard_inventory_delete'),
+    url(r'^item/(?P<item_pk>\d+)/change/$', views.item_change_availability, name='dashboard_inventory_change'),
     url(r'^item/(?P<item_pk>\d+)/batch/new/$', views.batch_new, name='dashboard_inventory_batch_new'),
     url(r'^item/(?P<item_pk>\d+)/batch/(?P<batch_pk>\d+)/$', views.batch, name='dashboard_inventory_batch'),
     url(r'^item/(?P<item_pk>\d+)/batch/(?P<batch_pk>\d+)/delete/$',
diff --git a/apps/inventory/dashboard/views.py b/apps/inventory/dashboard/views.py
--- a/apps/inventory/dashboard/views.py
+++ b/apps/inventory/dashboard/views.py
@@ -115,6 +115,23 @@
     raise PermissionDenied
 
 
+@login_required
+@permission_required('inventory.change_item', return_403=True)
+def item_change_availability(request, item_pk):
+    if not has_access(request):
+        raise PermissionDenied
+
+    item = get_object_or_404(Item, pk=item_pk)
+
+    # AJAX
+    if request.method == 'POST':
+        if request.is_ajax and 'action' in request.POST:
+            item.available = not item.available
+            item.save()
+
+            return JsonResponse({'message': 'OK', 'status': 200})
+
+
 @login_required
 @permission_required('inventory.add_batch', return_403=True)
 def batch_new(request, item_pk):

{"golden_diff": "diff --git a/apps/inventory/dashboard/urls.py b/apps/inventory/dashboard/urls.py\n--- a/apps/inventory/dashboard/urls.py\n+++ b/apps/inventory/dashboard/urls.py\n@@ -17,6 +17,7 @@\n     url(r'^new/$', views.new, name='dashboard_inventory_new'),\n     url(r'^item/(?P<item_pk>\\d+)/$', views.details, name='dashboard_inventory_details'),\n     url(r'^item/(?P<item_pk>\\d+)/delete/$', views.item_delete, name='dashboard_inventory_delete'),\n+    url(r'^item/(?P<item_pk>\\d+)/change/$', views.item_change_availability, name='dashboard_inventory_change'),\n     url(r'^item/(?P<item_pk>\\d+)/batch/new/$', views.batch_new, name='dashboard_inventory_batch_new'),\n     url(r'^item/(?P<item_pk>\\d+)/batch/(?P<batch_pk>\\d+)/$', views.batch, name='dashboard_inventory_batch'),\n     url(r'^item/(?P<item_pk>\\d+)/batch/(?P<batch_pk>\\d+)/delete/$',\ndiff --git a/apps/inventory/dashboard/views.py b/apps/inventory/dashboard/views.py\n--- a/apps/inventory/dashboard/views.py\n+++ b/apps/inventory/dashboard/views.py\n@@ -115,6 +115,23 @@\n     raise PermissionDenied\n \n \n+@login_required\n+@permission_required('inventory.change_item', return_403=True)\n+def item_change_availability(request, item_pk):\n+    if not has_access(request):\n+        raise PermissionDenied\n+\n+    item = get_object_or_404(Item, pk=item_pk)\n+\n+    # AJAX\n+    if request.method == 'POST':\n+        if request.is_ajax and 'action' in request.POST:\n+            item.available = not item.available\n+            item.save()\n+\n+            return JsonResponse({'message': 'OK', 'status': 200})\n+\n+\n @login_required\n @permission_required('inventory.add_batch', return_403=True)\n def batch_new(request, item_pk):\n", "issue": "Show if inventory item is available in nibble shop in product listing\n## What kind of an issue is this?\r\n\r\n- [x] Feature request\r\n\r\n\r\n## What is the expected behaviour?\r\n\r\nThere should be an icon in the dashboard product listing page that shows if an item is available for sale in Nibble.\r\n\r\nThis icon should also be clickable, to toggle whether or not the item should be available for sale in Nibble.\r\n\r\nIt should be possible to sort the items in the table according to the \"available for sale\"-state.\r\n\r\n\r\n## Other information\r\n\r\nThis is how an event's attendee list looks, and it could probably be done in the same way (look at the rightmost column): \r\n![screenshot 2017-02-27 17 05 03](https://cloud.githubusercontent.com/assets/5422571/23368846/7f1a2600-fd0f-11e6-9499-7afeedf65f76.png)\r\n\r\nThis is to be done in this list:\r\n![screenshot 2017-02-27 17 05 47](https://cloud.githubusercontent.com/assets/5422571/23368830/72016b18-fd0f-11e6-98f0-485ccebe14c7.png)\r\n\n", "before_files": [{"content": "# -*- encoding: utf-8 -*-\n\nfrom django.conf.urls import url\n\nfrom apps.inventory.dashboard import views\n\nurlpatterns = [\n    url(r'^$', views.index, name='dashboard_inventory_index'),\n    url(r'^statistics/$', views.statistics, name='dashboard_inventory_statistics'),\n    url(r'^statistics/orders/$', views.order_statistics, name='dashboard_inventory_order_statistics'),\n\n    url(r'^category/$', views.category_index, name='dashboard_category_index'),\n    url(r'^category/(?P<category_pk>\\d+)/$', views.category_details, name='dashboard_category_details'),\n    url(r'^category/new/$', views.category_new, name='dashboard_category_new'),\n    url(r'^category/(?P<category_pk>\\d+)/delete/$', views.category_delete, name='dashboard_category_delete'),\n\n    url(r'^new/$', views.new, name='dashboard_inventory_new'),\n    url(r'^item/(?P<item_pk>\\d+)/$', views.details, name='dashboard_inventory_details'),\n    url(r'^item/(?P<item_pk>\\d+)/delete/$', views.item_delete, name='dashboard_inventory_delete'),\n    url(r'^item/(?P<item_pk>\\d+)/batch/new/$', views.batch_new, name='dashboard_inventory_batch_new'),\n    url(r'^item/(?P<item_pk>\\d+)/batch/(?P<batch_pk>\\d+)/$', views.batch, name='dashboard_inventory_batch'),\n    url(r'^item/(?P<item_pk>\\d+)/batch/(?P<batch_pk>\\d+)/delete/$',\n        views.batch_delete,\n        name='dashboard_inventory_batch_delete'),\n]\n", "path": "apps/inventory/dashboard/urls.py"}, {"content": "# -*- encoding: utf-8 -*-\n\nfrom logging import getLogger\n\nfrom django.contrib import messages\nfrom django.contrib.auth.decorators import login_required\nfrom django.contrib.contenttypes.models import ContentType\nfrom django.core.exceptions import PermissionDenied\nfrom django.db.models import Count\nfrom django.http import JsonResponse\nfrom django.shortcuts import get_object_or_404, redirect, render\nfrom guardian.decorators import permission_required\n\nfrom apps.dashboard.tools import get_base_context, has_access\nfrom apps.inventory.dashboard.forms import BatchForm, CategoryForm, ItemForm\nfrom apps.inventory.models import Batch, Item, ItemCategory\nfrom apps.shop.models import Order\n\n\n@login_required\n@permission_required('inventory.view_item', return_403=True)\ndef index(request):\n\n    # Generic check to see if user has access to dashboard. (In Komiteer or superuser)\n    if not has_access(request):\n        raise PermissionDenied\n\n    # Create the base context needed for the sidebar\n    context = get_base_context(request)\n\n    context['items'] = Item.objects.all().order_by('name')\n\n    return render(request, 'inventory/dashboard/index.html', context)\n\n\n@login_required\n@permission_required('inventory.add_item', return_403=True)\ndef new(request):\n\n    if not has_access(request):\n        raise PermissionDenied\n\n    # Get base context\n    context = get_base_context(request)\n\n    if request.method == 'POST':\n        inventory_form = ItemForm(request.POST)\n\n        if not inventory_form.is_valid():\n            messages.error(request, 'Noen av de p\u00e5krevde feltene inneholder feil.')\n        else:\n            item = inventory_form.save()\n            messages.success(request, 'Varen ble opprettet')\n            return redirect(details, item.id)\n\n        context['form'] = inventory_form\n\n    else:\n        context['form'] = ItemForm()\n\n    return render(request, 'inventory/dashboard/new.html', context)\n\n\n@login_required\n@permission_required('inventory.view_item', return_403=True)\ndef details(request, item_pk):\n    # Generic check to see if user has access to dashboard. (In Komiteer or superuser)\n    if not has_access(request):\n        raise PermissionDenied\n\n    # Create the base context needed for the sidebar\n    context = get_base_context(request)\n\n    context['item'] = get_object_or_404(Item, pk=item_pk)\n\n    if request.method == 'POST':\n        if 'inventory.change_item' not in context['user_permissions']:\n            raise PermissionDenied\n\n        item_form = ItemForm(request.POST, instance=context['item'])\n        if not item_form.is_valid():\n            messages.error(request, 'Noen av de p\u00e5krevde feltene inneholder feil.')\n        else:\n            item_form.save()\n            messages.success(request, 'Varen ble oppdatert')\n        context['form'] = item_form\n    else:\n        context['form'] = ItemForm(instance=context['item'])\n\n    context['new_batch_form'] = BatchForm()\n\n    context['batch_forms'] = [\n        (b.id, BatchForm(instance=b)) for b in Batch.objects.filter(item=context['item'])\n    ]\n\n    return render(request, 'inventory/dashboard/details.html', context)\n\n\n@login_required\n@permission_required('inventory.delete_item', return_403=True)\ndef item_delete(request, item_pk):\n    if not has_access(request):\n        raise PermissionDenied\n\n    item = get_object_or_404(Item, pk=item_pk)\n\n    if request.method == 'POST':\n\n        item.delete()\n\n        messages.success(request, 'Varen %s ble slettet.' % item.name)\n\n        return redirect(index)\n\n    raise PermissionDenied\n\n\n@login_required\n@permission_required('inventory.add_batch', return_403=True)\ndef batch_new(request, item_pk):\n    if not has_access(request):\n        raise PermissionDenied\n\n    # Field mapper\n    fieldmap = {\n        'amount': 'Mengde',\n        'expiration_date': 'Utl\u00f8psdato',\n    }\n\n    item = get_object_or_404(Item, pk=item_pk)\n\n    if request.method == 'POST':\n        batch_form = BatchForm(request.POST)\n\n        if not batch_form.is_valid():\n            # Dirty hack to display errors since the form is not passed in redirect context\n            error_reply = \"Feil i felt:\"\n            for field, error in batch_form.errors.items():\n                error_reply += ' ' + fieldmap[field] + ' (' + batch_form.error_class.as_text(error) + '),'\n\n            messages.error(request, error_reply.rstrip(','))\n        else:\n            b = batch_form.save(commit=False)\n            b.item = item\n            b.save()\n            messages.success(request, 'Batchen ble lagt til.')\n\n        return redirect(details, item_pk=item_pk)\n\n    raise PermissionDenied\n\n\n@login_required\n@permission_required('inventory.change_batch', return_403=True)\ndef batch(request, item_pk, batch_pk):\n    if not has_access(request):\n        raise PermissionDenied\n\n    # Get base context\n\n    get_object_or_404(Item, pk=item_pk)\n    b = get_object_or_404(Batch, pk=batch_pk)\n\n    if request.method == 'POST':\n        batch_form = BatchForm(request.POST, instance=b)\n\n        if not batch_form.is_valid():\n            messages.error(request, 'Noen av de p\u00e5krevde feltene inneholder feil.')\n        else:\n            batch_form.save()\n            messages.success(request, 'Batchen ble oppdatert.')\n\n        return redirect(details, item_pk=item_pk)\n\n    raise PermissionDenied\n\n\n@login_required\n@permission_required('inventory.delete_batch', return_403=True)\ndef batch_delete(request, item_pk, batch_pk):\n    if not has_access(request):\n        raise PermissionDenied\n\n    b = get_object_or_404(Batch, pk=batch_pk)\n\n    if request.method == 'POST':\n\n        b.delete()\n        messages.success(request, 'Batchen ble slettet.')\n\n        return redirect(details, item_pk=item_pk)\n\n    raise PermissionDenied\n\n\n@login_required\n@permission_required('inventory.view_itemcategory', return_403=True)\ndef category_index(request):\n\n    # Generic check to see if user has access to dashboard. (In Komiteer or superuser)\n    if not has_access(request):\n        raise PermissionDenied\n\n    # Create the base context needed for the sidebar\n    context = get_base_context(request)\n\n    context['categories'] = ItemCategory.objects.all()\n\n    return render(request, 'inventory/dashboard/category_index.html', context)\n\n\n@login_required\n@permission_required('inventory.view_itemcategory', return_403=True)\ndef category_details(request, category_pk):\n    # Generic check to see if user has access to dashboard. (In Komiteer or superuser)\n    if not has_access(request):\n        raise PermissionDenied\n\n    # Create the base context needed for the sidebar\n    context = get_base_context(request)\n\n    context['category'] = get_object_or_404(ItemCategory, pk=category_pk)\n\n    if request.method == 'POST':\n\n        form = CategoryForm(request.POST, instance=context['category'])\n        if not form.is_valid():\n            messages.error(request, 'Noen av de p\u00e5krevde feltene inneholder feil.')\n        else:\n            form.save()\n            messages.success(request, 'Kategorien ble oppdatert')\n            return redirect(category_index)\n\n        context['form'] = form\n    else:\n        context['form'] = CategoryForm(instance=context['category'])\n\n    return render(request, 'inventory/dashboard/category_new.html', context)\n\n\n@login_required\n@permission_required('inventory.add_itemcategory', return_403=True)\ndef category_new(request):\n\n    if not has_access(request):\n        raise PermissionDenied\n\n    # Get base context\n    context = get_base_context(request)\n\n    if request.method == 'POST':\n        form = CategoryForm(request.POST)\n\n        if not form.is_valid():\n            messages.error(request, 'Noen av de p\u00e5krevde feltene inneholder feil.')\n        else:\n            form.save()\n            messages.success(request, 'Kategorien ble opprettet')\n            return redirect(category_index)\n\n        context['form'] = form\n    else:\n        context['form'] = CategoryForm()\n\n    return render(request, 'inventory/dashboard/category_new.html', context)\n\n\n@login_required\n@permission_required('inventory.delete_itemcategory', return_403=True)\ndef category_delete(request, category_pk):\n    if not has_access(request):\n        raise PermissionDenied\n\n    category = get_object_or_404(ItemCategory, pk=category_pk)\n\n    items = Item.objects.filter(category=category)\n\n    # Removes the category binding to prevent cascading delete\n    for item in items:\n        item.category = None\n        item.save()\n\n    category.delete()\n    messages.success(request, 'Kategorien %s ble slettet.' % category.name)\n    return redirect(category_index)\n\n    raise PermissionDenied\n\n\n@login_required\n# @permission_required('inventory.delete_batch', return_403=True)\ndef statistics(request):\n    # if not has_access(request):\n    #     raise PermissionDenied\n\n    context = get_base_context(request)\n\n    return render(request, 'inventory/dashboard/statistics.html', context)\n\n\n@login_required\ndef order_statistics(request):\n    # TODO check permissions\n\n    statistics = dict()\n\n    counts = Order.objects.all().values('object_id', 'content_type').annotate(total=Count('object_id'))\n    item_type = ContentType.objects.get_for_model(Item)\n\n    for count in counts:\n        print(count)\n        if item_type.id == count['content_type']:\n            try:\n                item = Item.objects.get(pk=count['object_id'])\n            except Item.DoesNotExist:\n                getLogger(__name__).error('Item with pk %s does not exist (DoesNotExist error)' % count['object_id'])\n            except KeyError:\n                getLogger(__name__).error('Key \"object_id\" does not exist')\n            if count['total'] > 0:\n                statistics[item.name] = count['total']\n\n    return JsonResponse(statistics)\n", "path": "apps/inventory/dashboard/views.py"}], "after_files": [{"content": "# -*- encoding: utf-8 -*-\n\nfrom django.conf.urls import url\n\nfrom apps.inventory.dashboard import views\n\nurlpatterns = [\n    url(r'^$', views.index, name='dashboard_inventory_index'),\n    url(r'^statistics/$', views.statistics, name='dashboard_inventory_statistics'),\n    url(r'^statistics/orders/$', views.order_statistics, name='dashboard_inventory_order_statistics'),\n\n    url(r'^category/$', views.category_index, name='dashboard_category_index'),\n    url(r'^category/(?P<category_pk>\\d+)/$', views.category_details, name='dashboard_category_details'),\n    url(r'^category/new/$', views.category_new, name='dashboard_category_new'),\n    url(r'^category/(?P<category_pk>\\d+)/delete/$', views.category_delete, name='dashboard_category_delete'),\n\n    url(r'^new/$', views.new, name='dashboard_inventory_new'),\n    url(r'^item/(?P<item_pk>\\d+)/$', views.details, name='dashboard_inventory_details'),\n    url(r'^item/(?P<item_pk>\\d+)/delete/$', views.item_delete, name='dashboard_inventory_delete'),\n    url(r'^item/(?P<item_pk>\\d+)/change/$', views.item_change_availability, name='dashboard_inventory_change'),\n    url(r'^item/(?P<item_pk>\\d+)/batch/new/$', views.batch_new, name='dashboard_inventory_batch_new'),\n    url(r'^item/(?P<item_pk>\\d+)/batch/(?P<batch_pk>\\d+)/$', views.batch, name='dashboard_inventory_batch'),\n    url(r'^item/(?P<item_pk>\\d+)/batch/(?P<batch_pk>\\d+)/delete/$',\n        views.batch_delete,\n        name='dashboard_inventory_batch_delete'),\n]\n", "path": "apps/inventory/dashboard/urls.py"}, {"content": "# -*- encoding: utf-8 -*-\n\nfrom logging import getLogger\n\nfrom django.contrib import messages\nfrom django.contrib.auth.decorators import login_required\nfrom django.contrib.contenttypes.models import ContentType\nfrom django.core.exceptions import PermissionDenied\nfrom django.db.models import Count\nfrom django.http import JsonResponse\nfrom django.shortcuts import get_object_or_404, redirect, render\nfrom guardian.decorators import permission_required\n\nfrom apps.dashboard.tools import get_base_context, has_access\nfrom apps.inventory.dashboard.forms import BatchForm, CategoryForm, ItemForm\nfrom apps.inventory.models import Batch, Item, ItemCategory\nfrom apps.shop.models import Order\n\n\n@login_required\n@permission_required('inventory.view_item', return_403=True)\ndef index(request):\n\n    # Generic check to see if user has access to dashboard. (In Komiteer or superuser)\n    if not has_access(request):\n        raise PermissionDenied\n\n    # Create the base context needed for the sidebar\n    context = get_base_context(request)\n\n    context['items'] = Item.objects.all().order_by('name')\n\n    return render(request, 'inventory/dashboard/index.html', context)\n\n\n@login_required\n@permission_required('inventory.add_item', return_403=True)\ndef new(request):\n\n    if not has_access(request):\n        raise PermissionDenied\n\n    # Get base context\n    context = get_base_context(request)\n\n    if request.method == 'POST':\n        inventory_form = ItemForm(request.POST)\n\n        if not inventory_form.is_valid():\n            messages.error(request, 'Noen av de p\u00e5krevde feltene inneholder feil.')\n        else:\n            item = inventory_form.save()\n            messages.success(request, 'Varen ble opprettet')\n            return redirect(details, item.id)\n\n        context['form'] = inventory_form\n\n    else:\n        context['form'] = ItemForm()\n\n    return render(request, 'inventory/dashboard/new.html', context)\n\n\n@login_required\n@permission_required('inventory.view_item', return_403=True)\ndef details(request, item_pk):\n    # Generic check to see if user has access to dashboard. (In Komiteer or superuser)\n    if not has_access(request):\n        raise PermissionDenied\n\n    # Create the base context needed for the sidebar\n    context = get_base_context(request)\n\n    context['item'] = get_object_or_404(Item, pk=item_pk)\n\n    if request.method == 'POST':\n        if 'inventory.change_item' not in context['user_permissions']:\n            raise PermissionDenied\n\n        item_form = ItemForm(request.POST, instance=context['item'])\n        if not item_form.is_valid():\n            messages.error(request, 'Noen av de p\u00e5krevde feltene inneholder feil.')\n        else:\n            item_form.save()\n            messages.success(request, 'Varen ble oppdatert')\n        context['form'] = item_form\n    else:\n        context['form'] = ItemForm(instance=context['item'])\n\n    context['new_batch_form'] = BatchForm()\n\n    context['batch_forms'] = [\n        (b.id, BatchForm(instance=b)) for b in Batch.objects.filter(item=context['item'])\n    ]\n\n    return render(request, 'inventory/dashboard/details.html', context)\n\n\n@login_required\n@permission_required('inventory.delete_item', return_403=True)\ndef item_delete(request, item_pk):\n    if not has_access(request):\n        raise PermissionDenied\n\n    item = get_object_or_404(Item, pk=item_pk)\n\n    if request.method == 'POST':\n\n        item.delete()\n\n        messages.success(request, 'Varen %s ble slettet.' % item.name)\n\n        return redirect(index)\n\n    raise PermissionDenied\n\n\n@login_required\n@permission_required('inventory.change_item', return_403=True)\ndef item_change_availability(request, item_pk):\n    if not has_access(request):\n        raise PermissionDenied\n\n    item = get_object_or_404(Item, pk=item_pk)\n\n    # AJAX\n    if request.method == 'POST':\n        if request.is_ajax and 'action' in request.POST:\n            item.available = not item.available\n            item.save()\n\n            return JsonResponse({'message': 'OK', 'status': 200})\n\n\n@login_required\n@permission_required('inventory.add_batch', return_403=True)\ndef batch_new(request, item_pk):\n    if not has_access(request):\n        raise PermissionDenied\n\n    # Field mapper\n    fieldmap = {\n        'amount': 'Mengde',\n        'expiration_date': 'Utl\u00f8psdato',\n    }\n\n    item = get_object_or_404(Item, pk=item_pk)\n\n    if request.method == 'POST':\n        batch_form = BatchForm(request.POST)\n\n        if not batch_form.is_valid():\n            # Dirty hack to display errors since the form is not passed in redirect context\n            error_reply = \"Feil i felt:\"\n            for field, error in batch_form.errors.items():\n                error_reply += ' ' + fieldmap[field] + ' (' + batch_form.error_class.as_text(error) + '),'\n\n            messages.error(request, error_reply.rstrip(','))\n        else:\n            b = batch_form.save(commit=False)\n            b.item = item\n            b.save()\n            messages.success(request, 'Batchen ble lagt til.')\n\n        return redirect(details, item_pk=item_pk)\n\n    raise PermissionDenied\n\n\n@login_required\n@permission_required('inventory.change_batch', return_403=True)\ndef batch(request, item_pk, batch_pk):\n    if not has_access(request):\n        raise PermissionDenied\n\n    # Get base context\n\n    get_object_or_404(Item, pk=item_pk)\n    b = get_object_or_404(Batch, pk=batch_pk)\n\n    if request.method == 'POST':\n        batch_form = BatchForm(request.POST, instance=b)\n\n        if not batch_form.is_valid():\n            messages.error(request, 'Noen av de p\u00e5krevde feltene inneholder feil.')\n        else:\n            batch_form.save()\n            messages.success(request, 'Batchen ble oppdatert.')\n\n        return redirect(details, item_pk=item_pk)\n\n    raise PermissionDenied\n\n\n@login_required\n@permission_required('inventory.delete_batch', return_403=True)\ndef batch_delete(request, item_pk, batch_pk):\n    if not has_access(request):\n        raise PermissionDenied\n\n    b = get_object_or_404(Batch, pk=batch_pk)\n\n    if request.method == 'POST':\n\n        b.delete()\n        messages.success(request, 'Batchen ble slettet.')\n\n        return redirect(details, item_pk=item_pk)\n\n    raise PermissionDenied\n\n\n@login_required\n@permission_required('inventory.view_itemcategory', return_403=True)\ndef category_index(request):\n\n    # Generic check to see if user has access to dashboard. (In Komiteer or superuser)\n    if not has_access(request):\n        raise PermissionDenied\n\n    # Create the base context needed for the sidebar\n    context = get_base_context(request)\n\n    context['categories'] = ItemCategory.objects.all()\n\n    return render(request, 'inventory/dashboard/category_index.html', context)\n\n\n@login_required\n@permission_required('inventory.view_itemcategory', return_403=True)\ndef category_details(request, category_pk):\n    # Generic check to see if user has access to dashboard. (In Komiteer or superuser)\n    if not has_access(request):\n        raise PermissionDenied\n\n    # Create the base context needed for the sidebar\n    context = get_base_context(request)\n\n    context['category'] = get_object_or_404(ItemCategory, pk=category_pk)\n\n    if request.method == 'POST':\n\n        form = CategoryForm(request.POST, instance=context['category'])\n        if not form.is_valid():\n            messages.error(request, 'Noen av de p\u00e5krevde feltene inneholder feil.')\n        else:\n            form.save()\n            messages.success(request, 'Kategorien ble oppdatert')\n            return redirect(category_index)\n\n        context['form'] = form\n    else:\n        context['form'] = CategoryForm(instance=context['category'])\n\n    return render(request, 'inventory/dashboard/category_new.html', context)\n\n\n@login_required\n@permission_required('inventory.add_itemcategory', return_403=True)\ndef category_new(request):\n\n    if not has_access(request):\n        raise PermissionDenied\n\n    # Get base context\n    context = get_base_context(request)\n\n    if request.method == 'POST':\n        form = CategoryForm(request.POST)\n\n        if not form.is_valid():\n            messages.error(request, 'Noen av de p\u00e5krevde feltene inneholder feil.')\n        else:\n            form.save()\n            messages.success(request, 'Kategorien ble opprettet')\n            return redirect(category_index)\n\n        context['form'] = form\n    else:\n        context['form'] = CategoryForm()\n\n    return render(request, 'inventory/dashboard/category_new.html', context)\n\n\n@login_required\n@permission_required('inventory.delete_itemcategory', return_403=True)\ndef category_delete(request, category_pk):\n    if not has_access(request):\n        raise PermissionDenied\n\n    category = get_object_or_404(ItemCategory, pk=category_pk)\n\n    items = Item.objects.filter(category=category)\n\n    # Removes the category binding to prevent cascading delete\n    for item in items:\n        item.category = None\n        item.save()\n\n    category.delete()\n    messages.success(request, 'Kategorien %s ble slettet.' % category.name)\n    return redirect(category_index)\n\n    raise PermissionDenied\n\n\n@login_required\n# @permission_required('inventory.delete_batch', return_403=True)\ndef statistics(request):\n    # if not has_access(request):\n    #     raise PermissionDenied\n\n    context = get_base_context(request)\n\n    return render(request, 'inventory/dashboard/statistics.html', context)\n\n\n@login_required\ndef order_statistics(request):\n    # TODO check permissions\n\n    statistics = dict()\n\n    counts = Order.objects.all().values('object_id', 'content_type').annotate(total=Count('object_id'))\n    item_type = ContentType.objects.get_for_model(Item)\n\n    for count in counts:\n        print(count)\n        if item_type.id == count['content_type']:\n            try:\n                item = Item.objects.get(pk=count['object_id'])\n            except Item.DoesNotExist:\n                getLogger(__name__).error('Item with pk %s does not exist (DoesNotExist error)' % count['object_id'])\n            except KeyError:\n                getLogger(__name__).error('Key \"object_id\" does not exist')\n            if count['total'] > 0:\n                statistics[item.name] = count['total']\n\n    return JsonResponse(statistics)\n", "path": "apps/inventory/dashboard/views.py"}]}