mirror of
https://github.com/ae-utbm/sith.git
synced 2024-11-25 02:24:26 +00:00
Addition of the ShoppingList view to know the item to buy
This commit is contained in:
parent
75af525945
commit
21c05cc779
@ -34,10 +34,10 @@
|
|||||||
{% endif %}
|
{% endif %}
|
||||||
{% if c.stock %}
|
{% if c.stock %}
|
||||||
<a href="{{ url('stock:items_list', stock_id=c.stock.id)}}">Stock</a> -
|
<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 %}
|
{% else %}
|
||||||
<a href="{{url('stock:new', counter_id=c.id)}}">{% trans %}Create new stock{% endtrans%}</a> -
|
<a href="{{url('stock:new', counter_id=c.id)}}">{% trans %}Create new stock{% endtrans%}</a> -
|
||||||
{% endif %}
|
{% endif %}
|
||||||
{% endif %}
|
|
||||||
{% if user.is_owner(c) %}
|
{% if user.is_owner(c) %}
|
||||||
<a href="{{ url('counter:prop_admin', counter_id=c.id) }}">{% trans %}Props{% endtrans %}</a>
|
<a href="{{ url('counter:prop_admin', counter_id=c.id) }}">{% trans %}Props{% endtrans %}</a>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
@ -88,6 +88,11 @@ class CounterTabsMixin(TabedViewMixin):
|
|||||||
'slug': 'last_ops',
|
'slug': 'last_ops',
|
||||||
'name': _("Last operations"),
|
'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
|
return tab_list
|
||||||
|
|
||||||
class CounterMain(CounterTabsMixin, CanViewMixin, DetailView, ProcessFormView, FormMixin):
|
class CounterMain(CounterTabsMixin, CanViewMixin, DetailView, ProcessFormView, FormMixin):
|
||||||
|
19
stock/migrations/0014_auto_20161228_1717.py
Normal file
19
stock/migrations/0014_auto_20161228_1717.py
Normal 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'),
|
||||||
|
),
|
||||||
|
]
|
@ -28,9 +28,24 @@ class StockItem(models.Model):
|
|||||||
on_delete=models.SET_NULL)
|
on_delete=models.SET_NULL)
|
||||||
stock_owner = models.ForeignKey(Stock, related_name="items")
|
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):
|
def __str__(self):
|
||||||
return "%s (%s)" % (self.name, self.effective_quantity)
|
return "%s (%s)" % (self.name, self.effective_quantity)
|
||||||
|
|
||||||
def get_absolute_url(self):
|
def get_absolute_url(self):
|
||||||
return reverse('stock:items_list', kwargs={'stock_id':self.stock_owner.id})
|
return reverse('stock:shoppinglist_list')
|
||||||
|
34
stock/templates/stock/shopping_list_items.jinja
Normal file
34
stock/templates/stock/shopping_list_items.jinja
Normal 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 %}
|
@ -7,7 +7,7 @@
|
|||||||
{% block content %}
|
{% block content %}
|
||||||
{% if current_tab == "stocks" %}
|
{% if current_tab == "stocks" %}
|
||||||
<p><a href="{{ url('stock:new_item', stock_id=stock.id)}}">{% trans %}New item{% endtrans %}</a></p>
|
<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 %}
|
{% endif %}
|
||||||
{% if stock %}
|
{% if stock %}
|
||||||
<h3>{{ stock }}</h3>
|
<h3>{{ stock }}</h3>
|
||||||
|
@ -13,6 +13,7 @@
|
|||||||
{% if user.can_edit(s) %}
|
{% if user.can_edit(s) %}
|
||||||
<a href="{{ url('stock:items_list', stock_id=s.id) }}">{{s}}</a>
|
<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:edit', stock_id=s.id) }}">Edit</a>
|
||||||
|
- <a href="{{ url('stock:shoppinglist_list', stock_id=s.id)}}">{% trans %}Shopping lists{% endtrans %}</a>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
</li>
|
</li>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
|
@ -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 %}
|
|
||||||
|
|
@ -5,6 +5,60 @@ Shopping list for {{ stock }}
|
|||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
||||||
{% block content %}
|
{% 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 %}
|
{% endblock %}
|
@ -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]+)$', StockItemList.as_view(), name='items_list'),
|
||||||
url(r'^(?P<stock_id>[0-9]+)/stockItem/newItem$', StockItemCreateView.as_view(), name='new_item'),
|
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'^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'),
|
||||||
]
|
]
|
||||||
|
136
stock/views.py
136
stock/views.py
@ -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.views.generic.edit import UpdateView, CreateView, DeleteView, ProcessFormView, FormMixin
|
||||||
from django.utils.translation import ugettext_lazy as _
|
from django.utils.translation import ugettext_lazy as _
|
||||||
from django import forms
|
from django import forms
|
||||||
|
from django.http import HttpResponseRedirect, HttpResponse
|
||||||
from django.forms.models import modelform_factory
|
from django.forms.models import modelform_factory
|
||||||
from django.core.urlresolvers import reverse_lazy, reverse
|
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();
|
ret['stock'] = Stock.objects.filter(id=self.kwargs['stock_id']).first();
|
||||||
return ret
|
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
|
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}))
|
||||||
|
Loading…
Reference in New Issue
Block a user