Addition of the ShoppingList view to know the item to buy

This commit is contained in:
guillaume-renaud 2016-12-28 19:25:43 +01:00
parent 75af525945
commit 21c05cc779
11 changed files with 280 additions and 18 deletions

View File

@ -32,12 +32,12 @@
<a href="{{ url('counter:admin', counter_id=c.id) }}">{% trans %}Edit{% endtrans %}</a> -
<a href="{{ url('counter:stats', counter_id=c.id) }}">{% trans %}Stats{% endtrans %}</a> -
{% endif %}
{%if c.stock %}
{% if c.stock %}
<a href="{{ url('stock:items_list', stock_id=c.stock.id)}}">Stock</a> -
<a href="{{ url('stock:shoppinglist_list', stock_id=c.stock.id)}}">{% trans %}Shopping lists{% endtrans %}</a> -
{% else %}
<a href="{{url('stock:new', counter_id=c.id)}}">{% trans %}Create new stock{% endtrans%}</a> -
{% endif %}
{% endif %}
{% if user.is_owner(c) %}
<a href="{{ url('counter:prop_admin', counter_id=c.id) }}">{% trans %}Props{% endtrans %}</a>
{% endif %}

View File

@ -88,6 +88,11 @@ class CounterTabsMixin(TabedViewMixin):
'slug': 'last_ops',
'name': _("Last operations"),
})
tab_list.append({
'url': reverse_lazy('stock:items_list', kwargs={'stock_id': self.object.stock.id}),
'slug': 'stock_items_list',
'name': _("Stock items list"),
})
return tab_list
class CounterMain(CounterTabsMixin, CanViewMixin, DetailView, ProcessFormView, FormMixin):

View File

@ -0,0 +1,19 @@
# -*- coding: utf-8 -*-
from __future__ import unicode_literals
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('stock', '0013_auto_20161228_1006'),
]
operations = [
migrations.AlterField(
model_name='shoppinglist',
name='stock_owner',
field=models.ForeignKey(related_name='shopping_lists', null=True, to='stock.Stock'),
),
]

View File

@ -28,9 +28,24 @@ class StockItem(models.Model):
on_delete=models.SET_NULL)
stock_owner = models.ForeignKey(Stock, related_name="items")
def __str__(self):
return "%s" % (self.name)
def get_absolute_url(self):
return reverse('stock:items_list', kwargs={'stock_id':self.stock_owner.id})
class ShoppingList(models.Model):
"""
The ShoppingList class, used to make an history of the shopping lists
"""
date = models.DateTimeField(_('date'))
name = models.CharField(_('name'), max_length=64)
todo = models.BooleanField(_('todo'))
items_to_buy = models.ManyToManyField(StockItem, verbose_name=_('items to buy'), related_name="shopping_lists")
stock_owner = models.ForeignKey(Stock, null=True, related_name="shopping_lists")
def __str__(self):
return "%s (%s)" % (self.name, self.effective_quantity)
def get_absolute_url(self):
return reverse('stock:items_list', kwargs={'stock_id':self.stock_owner.id})
return reverse('stock:shoppinglist_list')

View File

@ -0,0 +1,34 @@
{% extends "core/base.jinja" %}
{% block title %}
{% trans %}{{ shoppinglist }}'s items{% endtrans %}
{% endblock %}
{% block content %}
{% if current_tab == "stocks" %}
<a href="{{ url('stock:shoppinglist_list', stock_id=shoppinglist.stock_owner.id)}}">{% trans %}Back{% endtrans %}</a>
{% endif %}
<h3>{{ shoppinglist.name }}</h3>
{% for t in ProductType.objects.order_by('name') %}
{% if shoppinglist.items_to_buy.filter(type=t) %}
<h4>{{ t }}</h4>
<table>
<thead>
<tr>
<td>{% trans %}Name{% endtrans %}</td>
<td>{% trans %}Number{% endtrans %}</td>
</tr>
</thead>
<tbody>
{% for i in shoppinglist.items_to_buy.filter(type=t).order_by('name') %}
<tr>
<td>{{ i.name }}</td>
<td>{{ i.tobuy_quantity }}</td>
</tr>
{% endfor %}
</tbody>
</table>
{% endif %}
{% endfor %}
{% endblock %}

View File

@ -7,7 +7,7 @@
{% block content %}
{% if current_tab == "stocks" %}
<p><a href="{{ url('stock:new_item', stock_id=stock.id)}}">{% trans %}New item{% endtrans %}</a></p>
<h5><a href="{{ url('stock:shopping_list', stock_id=stock.id)}}">{% trans %}Shopping list{% endtrans %}</a></h5>
<h5><a href="{{ url('stock:shoppinglist_list', stock_id=stock.id)}}">{% trans %}Shopping list{% endtrans %}</a></h5>
{% endif %}
{% if stock %}
<h3>{{ stock }}</h3>

View File

@ -13,6 +13,7 @@
{% if user.can_edit(s) %}
<a href="{{ url('stock:items_list', stock_id=s.id) }}">{{s}}</a>
- <a href="{{ url('stock:edit', stock_id=s.id) }}">Edit</a>
- <a href="{{ url('stock:shoppinglist_list', stock_id=s.id)}}">{% trans %}Shopping lists{% endtrans %}</a>
{% endif %}
</li>
{% endfor %}

View File

@ -1,11 +0,0 @@
{% extends "core/base.jinja" %}
{% block title %}
{{stock}}
{% endblock %}
{% block content %}
<h3>{{stock}}</h3>
<a href="{{ url('stock:new_item', stock_id=stock.id) }}">{% trans %}New Item{% endtrans %}</a>
{% endblock %}

View File

@ -5,6 +5,60 @@ Shopping list for {{ stock }}
{% endblock %}
{% block content %}
<h3>Shopping list for {{ stock }}</h3>
{% if current_tab == "stocks" %}
<a href="{{ url('stock:shoppinglist_create', stock_id=stock.id)}}">{% trans %}Do shopping{% endtrans %}</a>
{% endif %}
<h3>{% trans s=stock %}Shopping lists history for {{ s }}{% endtrans %}</h3>
<h4>To do</h4>
<table>
<thead>
<tr>
<td>{% trans %}Date{% endtrans %}</td>
<td>{% trans %}Name{% endtrans %}</td>
<td>{% trans %}Number of items{% endtrans %}</td>
</tr>
</thead>
<tbody>
{% for s in shoppinglist_list.filter(todo=True).filter(stock_owner=stock).order_by('-date') %}
<tr>
<td>{{ s.date|localtime|date("Y-m-d H:i") }}</td>
<td><a href="{{ url('stock:shoppinglist_items', stock_id=stock.id, shoppinglist_id=s.id)}}">{{ s.name }}</a></td>
<td>{{ s.items_to_buy.count() }}</td>
<td>
<a href="{{ url('stock:shoppinglist_set_done', stock_id=stock.id, shoppinglist_id=s.id)}}">{% trans %}Mark as done{% endtrans %}</a>
</td>
<td>
<a href="{{ url('stock:shoppinglist_delete', stock_id=stock.id, shoppinglist_id=s.id)}}">{% trans %}Delete{% endtrans %}</a>
</td>
</tr>
{% endfor %}
</tbody>
</table>
<h4>Done</h4>
<table>
<thead>
<tr>
<td>{% trans %}Date{% endtrans %}</td>
<td>{% trans %}Name{% endtrans %}</td>
<td>{% trans %}Number of items{% endtrans %}</td>
</tr>
</thead>
<tbody>
{% for s in shoppinglist_list.filter(todo=False).filter(stock_owner=stock).order_by('-date') %}
<tr>
<td>{{ s.date|localtime|date("Y-m-d H:i") }}</td>
<td><a href="{{ url('stock:shoppinglist_items', stock_id=stock.id, shoppinglist_id=s.id)}}">{{ s.name }}</a></td>
<td>{{ s.items_to_buy.count() }}</td>
<td>
<a href="{{ url('stock:shoppinglist_set_todo', stock_id=stock.id, shoppinglist_id=s.id)}}">{% trans %}Mark as todo{% endtrans %}</a>
</td>
<td>
<a href="{{ url('stock:shoppinglist_delete', stock_id=stock.id, shoppinglist_id=s.id)}}">{% trans %}Delete{% endtrans %}</a>
</td>
</tr>
{% endfor %}
</tbody>
</table>
{% endblock %}

View File

@ -12,5 +12,16 @@ urlpatterns = [
url(r'^(?P<stock_id>[0-9]+)$', StockItemList.as_view(), name='items_list'),
url(r'^(?P<stock_id>[0-9]+)/stockItem/newItem$', StockItemCreateView.as_view(), name='new_item'),
url(r'^stockItem/(?P<item_id>[0-9]+)/edit$', StockItemEditView.as_view(), name='edit_item'),
url(r'^(?P<stock_id>[0-9]+)/shopping$', StockShoppingListView.as_view(), name='shopping_list'),
# ShoppingList urls
url(r'^(?P<stock_id>[0-9]+)/shoppingList/list$', StockShoppingListView.as_view(), name='shoppinglist_list'),
url(r'^(?P<stock_id>[0-9]+)/shoppingList/create$', StockItemQuantityBaseFormView.as_view(), name='shoppinglist_create'),
url(r'^(?P<stock_id>[0-9]+)/shoppingList/(?P<shoppinglist_id>[0-9]+)/items$', StockShoppingListItemListView.as_view(),
name='shoppinglist_items'),
url(r'^(?P<stock_id>[0-9]+)/shoppingList/(?P<shoppinglist_id>[0-9]+)/delete$', StockShoppingListDeleteView.as_view(),
name='shoppinglist_delete'),
url(r'^(?P<stock_id>[0-9]+)/shoppingList/(?P<shoppinglist_id>[0-9]+)/setDone$', StockShopppingListSetDone.as_view(),
name='shoppinglist_set_done'),
url(r'^(?P<stock_id>[0-9]+)/shoppingList/(?P<shoppinglist_id>[0-9]+)/setTodo$', StockShopppingListSetTodo.as_view(),
name='shoppinglist_set_todo'),
]

View File

@ -3,6 +3,7 @@ from django.views.generic import ListView, DetailView, RedirectView, TemplateVie
from django.views.generic.edit import UpdateView, CreateView, DeleteView, ProcessFormView, FormMixin
from django.utils.translation import ugettext_lazy as _
from django import forms
from django.http import HttpResponseRedirect, HttpResponse
from django.forms.models import modelform_factory
from django.core.urlresolvers import reverse_lazy, reverse
@ -159,7 +160,140 @@ class StockShoppingListView(CounterAdminTabsMixin, CanViewMixin, ListView):
ret['stock'] = Stock.objects.filter(id=self.kwargs['stock_id']).first();
return ret
class StockItemOutEditView(CounterAdminTabsMixin, CanViewMixin, UpdateView):
class StockItemQuantityForm(forms.BaseForm):
def clean(self):
with transaction.atomic():
self.stock = Stock.objects.filter(id=self.stock_id).first()
shopping_list = ShoppingList(name="Courses "+self.stock.counter.name, date=timezone.now(), todo=True)
shopping_list.save()
shopping_list.stock_owner = self.stock
shopping_list.save()
for k,t in self.cleaned_data.items():
if t is not None:
item_id = int(k[5:])
item = StockItem.objects.filter(id=item_id).first()
item.tobuy_quantity = t
item.shopping_lists.add(shopping_list)
item.save()
return self.cleaned_data
class StockItemQuantityBaseFormView(CounterAdminTabsMixin, CanEditMixin, DetailView, BaseFormView):
"""
docstring for StockItemOutList
"""
model = StockItem
template_name = "stock/shopping_list_quantity.jinja"
pk_url_kwarg = "stock_id"
current_tab = "stocks"
def get_form_class(self):
fields = OrderedDict()
kwargs = {}
for t in ProductType.objects.order_by('name').all():
for i in self.stock.items.filter(type=t).order_by('name').all():
if i.effective_quantity <= i.minimal_quantity:
field_name = "item-%s" % (str(i.id))
fields[field_name] = forms.CharField(max_length=30, required=True, label=str(i),
help_text=str(i.effective_quantity)+" left")
kwargs[field_name] = i.effective_quantity
kwargs['stock_id'] = self.stock.id
kwargs['base_fields'] = fields
return type('StockItemQuantityForm', (StockItemQuantityForm,), kwargs)
def get(self, request, *args, **kwargs):
"""
Simple get view
"""
self.stock = Stock.objects.filter(id=self.kwargs['stock_id']).first()
return super(StockItemQuantityBaseFormView, self).get(request, *args, **kwargs)
def post(self, request, *args, **kwargs):
"""
Handle the many possibilities of the post request
"""
self.object = self.get_object()
self.stock = Stock.objects.filter(id=self.kwargs['stock_id']).first()
return super(StockItemQuantityBaseFormView, self).post(request, *args, **kwargs)
def form_valid(self, form):
"""
We handle here the redirection, passing the user id of the asked customer
"""
return super(StockItemQuantityBaseFormView, self).form_valid(form)
def get_context_data(self, **kwargs):
"""
We handle here the login form for the barman
"""
kwargs = super(StockItemQuantityBaseFormView, self).get_context_data(**kwargs)
if 'form' not in kwargs.keys():
kwargs['form'] = self.get_form()
kwargs['stock'] = self.stock
return kwargs
def get_success_url(self):
return reverse_lazy('stock:shoppinglist_list', args=self.args, kwargs=self.kwargs)
class StockShoppingListItemListView(CounterAdminTabsMixin, CanViewMixin, ListView):
"""docstring for StockShoppingListItemListView"""
model = ShoppingList
template_name = "stock/shopping_list_items.jinja"
pk_url_kwarg = "shoppinglist_id"
current_tab = "stocks"
def get_context_data(self):
ret = super(StockShoppingListItemListView, self).get_context_data()
if 'shoppinglist_id' in self.kwargs.keys():
ret['shoppinglist'] = ShoppingList.objects.filter(id=self.kwargs['shoppinglist_id']).first();
return ret
class StockShoppingListDeleteView(CounterAdminTabsMixin, CanEditMixin, DeleteView):
"""
Delete a ShoppingList (for the resonsible account)
"""
model = ShoppingList
pk_url_kwarg = "shoppinglist_id"
template_name = 'core/delete_confirm.jinja'
current_tab = "stocks"
def get_success_url(self):
return reverse_lazy('stock:shoppinglist_list', kwargs={'stock_id':self.object.stock_owner.id})
class StockShopppingListSetDone(CanEditMixin, DetailView):
"""
Set a ShoppingList as done
"""
model = ShoppingList
pk_url_kwarg = "shoppinglist_id"
def get(self, request, *args, **kwargs):
self.object = self.get_object()
self.object.todo = False
self.object.save()
return HttpResponseRedirect(reverse('stock:shoppinglist_list', args=self.args, kwargs={'stock_id':self.object.stock_owner.id}))
def post(self, request, *args, **kwargs):
self.object = self.get_object()
return HttpResponseRedirect(reverse('stock:shoppinglist_list', args=self.args, kwargs={'stock_id':self.object.stock_owner.id}))
class StockShopppingListSetTodo(CanEditMixin, DetailView):
"""
Set a ShoppingList as done
"""
model = ShoppingList
pk_url_kwarg = "shoppinglist_id"
def get(self, request, *args, **kwargs):
self.object = self.get_object()
self.object.todo = True
self.object.save()
return HttpResponseRedirect(reverse('stock:shoppinglist_list', args=self.args, kwargs={'stock_id':self.object.stock_owner.id}))
def post(self, request, *args, **kwargs):
self.object = self.get_object()
return HttpResponseRedirect(reverse('stock:shoppinglist_list', args=self.args, kwargs={'stock_id':self.object.stock_owner.id}))