Update shopping list history (ShoppingListItem creation)

This commit is contained in:
guillaume-renaud 2017-01-07 11:17:06 +01:00
parent 62200827c2
commit 539faccab2
15 changed files with 337 additions and 109 deletions

View File

@ -1,7 +1,9 @@
from django.contrib import admin
from stock.models import Stock, StockItem
from stock.models import Stock, StockItem, ShoppingList, ShoppingListItem
# Register your models here.
admin.site.register(Stock)
admin.site.register(StockItem)
admin.site.register(StockItem)
admin.site.register(ShoppingList)
admin.site.register(ShoppingListItem)

View File

@ -2,6 +2,7 @@
from __future__ import unicode_literals
from django.db import migrations, models
import django.db.models.deletion
class Migration(migrations.Migration):
@ -11,22 +12,42 @@ class Migration(migrations.Migration):
]
operations = [
migrations.CreateModel(
name='ShoppingList',
fields=[
('id', models.AutoField(primary_key=True, auto_created=True, serialize=False, verbose_name='ID')),
('date', models.DateTimeField(verbose_name='date')),
('name', models.CharField(max_length=64, verbose_name='name')),
('todo', models.BooleanField(verbose_name='todo')),
],
),
migrations.CreateModel(
name='Stock',
fields=[
('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)),
('id', models.AutoField(primary_key=True, auto_created=True, serialize=False, verbose_name='ID')),
('name', models.CharField(max_length=64, verbose_name='name')),
('counter', models.OneToOneField(to='counter.Counter', related_name='stock', verbose_name='counter')),
('counter', models.OneToOneField(to='counter.Counter', verbose_name='counter', related_name='stock')),
],
),
migrations.CreateModel(
name='StockItem',
fields=[
('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)),
('id', models.AutoField(primary_key=True, auto_created=True, serialize=False, verbose_name='ID')),
('name', models.CharField(max_length=64, verbose_name='name')),
('unit_quantity', models.IntegerField(default=0, verbose_name='unit quantity')),
('effective_quantity', models.IntegerField(default=0, verbose_name='effective quantity')),
('stock_owner', models.ForeignKey(related_name='stock_owner', to='stock.Stock')),
('unit_quantity', models.IntegerField(default=0, help_text='number of element in one box', verbose_name='unit quantity')),
('effective_quantity', models.IntegerField(default=0, help_text='number of box', verbose_name='effective quantity')),
('stock_owner', models.ForeignKey(to='stock.Stock', related_name='items')),
('type', models.ForeignKey(to='counter.ProductType', on_delete=django.db.models.deletion.SET_NULL, null=True, verbose_name='type', blank=True, related_name='stock_items')),
],
),
migrations.AddField(
model_name='shoppinglist',
name='items_to_buy',
field=models.ManyToManyField(to='stock.StockItem', related_name='shopping_lists', verbose_name='items to buy'),
),
migrations.AddField(
model_name='shoppinglist',
name='stock_owner',
field=models.ForeignKey(to='stock.Stock', null=True, related_name='shopping_lists'),
),
]

View File

@ -1,31 +0,0 @@
# -*- coding: utf-8 -*-
from __future__ import unicode_literals
from django.db import migrations, models
import django.db.models.deletion
class Migration(migrations.Migration):
dependencies = [
('counter', '0011_auto_20161004_2039'),
('stock', '0001_initial'),
]
operations = [
migrations.AddField(
model_name='stockitem',
name='type',
field=models.ForeignKey(to='counter.ProductType', blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, verbose_name='type', related_name='stockItem_type'),
),
migrations.AlterField(
model_name='stockitem',
name='effective_quantity',
field=models.IntegerField(help_text='total number of bottle/barrel', verbose_name='effective quantity', default=0),
),
migrations.AlterField(
model_name='stockitem',
name='unit_quantity',
field=models.IntegerField(help_text='number of beer in one crate (equal one for barrels)', verbose_name='unit quantity', default=0),
),
]

View File

@ -0,0 +1,29 @@
# -*- coding: utf-8 -*-
from __future__ import unicode_literals
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('stock', '0001_initial'),
]
operations = [
migrations.AddField(
model_name='stockitem',
name='bought_quantity',
field=models.IntegerField(help_text='quantity bought during the last shopping session', default=6, verbose_name='quantity bought'),
),
migrations.AddField(
model_name='stockitem',
name='minimal_quantity',
field=models.IntegerField(help_text='if the effective quantity is less than the minimal, item is added to the shopping list', default=1, verbose_name='minimal quantity'),
),
migrations.AddField(
model_name='stockitem',
name='tobuy_quantity',
field=models.IntegerField(help_text='quantity to buy during the next shopping session', default=6, verbose_name='quantity to buy'),
),
]

View File

@ -1,35 +0,0 @@
# -*- coding: utf-8 -*-
from __future__ import unicode_literals
from django.db import migrations, models
import django.db.models.deletion
class Migration(migrations.Migration):
dependencies = [
('stock', '0002_auto_20161113_2325'),
]
operations = [
migrations.AlterField(
model_name='stockitem',
name='effective_quantity',
field=models.IntegerField(default=0, verbose_name='effective quantity', help_text='number of box'),
),
migrations.AlterField(
model_name='stockitem',
name='stock_owner',
field=models.ForeignKey(related_name='items', to='stock.Stock'),
),
migrations.AlterField(
model_name='stockitem',
name='type',
field=models.ForeignKey(related_name='stock_items', verbose_name='type', null=True, to='counter.ProductType', blank=True, on_delete=django.db.models.deletion.SET_NULL),
),
migrations.AlterField(
model_name='stockitem',
name='unit_quantity',
field=models.IntegerField(default=0, verbose_name='unit quantity', help_text='number of element in one box'),
),
]

View File

@ -0,0 +1,32 @@
# -*- coding: utf-8 -*-
from __future__ import unicode_literals
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('stock', '0002_auto_20170105_2017'),
]
operations = [
migrations.RemoveField(
model_name='stockitem',
name='bought_quantity',
),
migrations.RemoveField(
model_name='stockitem',
name='tobuy_quantity',
),
migrations.AddField(
model_name='shoppinglist',
name='bought_quantity',
field=models.IntegerField(help_text='quantity bought during the last shopping session', default=6, verbose_name='quantity bought'),
),
migrations.AddField(
model_name='shoppinglist',
name='tobuy_quantity',
field=models.IntegerField(help_text='quantity to buy during the next shopping session', default=6, verbose_name='quantity to buy'),
),
]

View File

@ -0,0 +1,32 @@
# -*- coding: utf-8 -*-
from __future__ import unicode_literals
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('stock', '0003_auto_20170105_2138'),
]
operations = [
migrations.RemoveField(
model_name='shoppinglist',
name='bought_quantity',
),
migrations.RemoveField(
model_name='shoppinglist',
name='tobuy_quantity',
),
migrations.AddField(
model_name='stockitem',
name='bought_quantity',
field=models.IntegerField(help_text='quantity bought during the last shopping session', verbose_name='quantity bought', default=6),
),
migrations.AddField(
model_name='stockitem',
name='tobuy_quantity',
field=models.IntegerField(help_text='quantity to buy during the next shopping session', verbose_name='quantity to buy', default=6),
),
]

View File

@ -0,0 +1,46 @@
# -*- coding: utf-8 -*-
from __future__ import unicode_literals
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('stock', '0004_auto_20170105_2145'),
]
operations = [
migrations.CreateModel(
name='ShoppingListItems',
fields=[
('id', models.AutoField(primary_key=True, auto_created=True, verbose_name='ID', serialize=False)),
('name', models.CharField(max_length=64, verbose_name='name')),
('tobuy_quantity', models.IntegerField(verbose_name='quantity to buy', default=6, help_text='quantity to buy during the next shopping session')),
('bought_quantity', models.IntegerField(verbose_name='quantity bought', default=6, help_text='quantity bought during the last shopping session')),
],
),
migrations.RemoveField(
model_name='stockitem',
name='bought_quantity',
),
migrations.RemoveField(
model_name='stockitem',
name='tobuy_quantity',
),
migrations.AddField(
model_name='shoppinglist',
name='comment',
field=models.TextField(null=True, verbose_name='comment', blank=True),
),
migrations.AddField(
model_name='shoppinglistitems',
name='shoppinglist_owner',
field=models.ForeignKey(related_name='item_quantity', to='stock.ShoppingList'),
),
migrations.AddField(
model_name='shoppinglistitems',
name='stockitem_owner',
field=models.ForeignKey(related_name='item', null=True, to='stock.StockItem'),
),
]

View File

@ -0,0 +1,48 @@
# -*- coding: utf-8 -*-
from __future__ import unicode_literals
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('stock', '0005_auto_20170107_0857'),
]
operations = [
migrations.CreateModel(
name='ShoppingListItem',
fields=[
('id', models.AutoField(serialize=False, auto_created=True, primary_key=True, verbose_name='ID')),
('name', models.CharField(max_length=64, verbose_name='name')),
('tobuy_quantity', models.IntegerField(default=6, help_text='quantity to buy during the next shopping session', verbose_name='quantity to buy')),
('bought_quantity', models.IntegerField(default=0, help_text='quantity bought during the last shopping session', verbose_name='quantity bought')),
],
),
migrations.RemoveField(
model_name='shoppinglistitems',
name='shoppinglist_owner',
),
migrations.RemoveField(
model_name='shoppinglistitems',
name='stockitem_owner',
),
migrations.RemoveField(
model_name='shoppinglist',
name='items_to_buy',
),
migrations.DeleteModel(
name='ShoppingListItems',
),
migrations.AddField(
model_name='shoppinglistitem',
name='shopping_lists',
field=models.ManyToManyField(related_name='shopping_items_to_buy', to='stock.ShoppingList', verbose_name='shopping lists'),
),
migrations.AddField(
model_name='shoppinglistitem',
name='stockitem_owner',
field=models.ForeignKey(related_name='item', null=True, to='stock.StockItem'),
),
]

View File

@ -0,0 +1,21 @@
# -*- coding: utf-8 -*-
from __future__ import unicode_literals
from django.db import migrations, models
import django.db.models.deletion
class Migration(migrations.Migration):
dependencies = [
('counter', '0011_auto_20161004_2039'),
('stock', '0006_auto_20170107_0910'),
]
operations = [
migrations.AddField(
model_name='shoppinglistitem',
name='type',
field=models.ForeignKey(null=True, verbose_name='type', on_delete=django.db.models.deletion.SET_NULL, to='counter.ProductType', blank=True, related_name='shoppinglist_items'),
),
]

View File

@ -7,13 +7,13 @@ from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('stock', '0013_auto_20161228_1006'),
('stock', '0007_shoppinglistitem_type'),
]
operations = [
migrations.AlterField(
model_name='shoppinglist',
name='stock_owner',
field=models.ForeignKey(related_name='shopping_lists', null=True, to='stock.Stock'),
model_name='shoppinglistitem',
name='stockitem_owner',
field=models.ForeignKey(related_name='shopping_item', to='stock.StockItem', null=True),
),
]

View File

@ -29,6 +29,8 @@ class StockItem(models.Model):
name = models.CharField(_('name'), max_length=64)
unit_quantity = models.IntegerField(_('unit quantity'), default=0, help_text='number of element in one box')
effective_quantity = models.IntegerField(_('effective quantity'), default=0, help_text='number of box')
minimal_quantity = models.IntegerField(_('minimal quantity'), default=1,
help_text='if the effective quantity is less than the minimal, item is added to the shopping list')
type = models.ForeignKey(ProductType, related_name="stock_items", verbose_name=_("type"), null=True, blank=True,
on_delete=models.SET_NULL)
stock_owner = models.ForeignKey(Stock, related_name="items")
@ -49,14 +51,36 @@ class ShoppingList(models.Model):
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")
comment = models.TextField(_('comment'), null=True, blank=True)
stock_owner = models.ForeignKey(Stock, null=True, related_name="shopping_lists")
def __str__(self):
return "%s (%s)" % (self.name, self.effective_quantity)
return "%s (%s)" % (self.name, self.date)
def get_absolute_url(self):
return reverse('stock:shoppinglist_list')
def can_be_viewed_by(self, user):
return user.is_in_group(settings.SITH_GROUP_COUNTER_ADMIN_ID)
class ShoppingListItem(models.Model):
"""
"""
shopping_lists = models.ManyToManyField(ShoppingList, verbose_name=_('shopping lists'), related_name="shopping_items_to_buy")
stockitem_owner = models.ForeignKey(StockItem, related_name="shopping_item", null=True)
name = models.CharField(_('name'), max_length=64)
type = models.ForeignKey(ProductType, related_name="shoppinglist_items", verbose_name=_("type"), null=True, blank=True,
on_delete=models.SET_NULL)
tobuy_quantity = models.IntegerField(_('quantity to buy'), default=6, help_text="quantity to buy during the next shopping session")
bought_quantity = models.IntegerField(_('quantity bought'), default=0, help_text="quantity bought during the last shopping session")
def __str__(self):
return "%s - %s" % (self.name, self.shopping_lists.first())
def can_be_viewed_by(self, user):
return user.is_in_group(settings.SITH_GROUP_COUNTER_ADMIN_ID)
def get_absolute_url(self):
return reverse('stock:shoppinglist_list')

View File

@ -10,25 +10,42 @@
{% endif %}
<h3>{{ shoppinglist.name }}</h3>
{% for t in ProductType.objects.order_by('name') %}
{% if shoppinglist.items_to_buy.filter(type=t) %}
{% for t in ProductType.objects.order_by('name').all() %}
{% if shoppinglist.shopping_items_to_buy.filter(type=t) %}
<h4>{{ t }}</h4>
<br>
<table>
<thead>
<tr>
<td>{% trans %}Name{% endtrans %}</td>
<td>{% trans %}Number{% endtrans %}</td>
<td>{% trans %}Quantity asked{% endtrans %}</td>
<td>{% trans %}Quantity bought{% endtrans %}</td>
</tr>
</thead>
<tbody>
{% for i in shoppinglist.items_to_buy.filter(type=t).order_by('name') %}
{% for i in shoppinglist.shopping_items_to_buy.filter(type=t).order_by('name').all() %}
<tr>
<td>{{ i.name }}</td>
<td>{{ i.tobuy_quantity }}</td>
<td>{{ i.bought_quantity }}</td>
</tr>
{% endfor %}
</tbody>
</table>
{% endif %}
{% endfor %}
<h4>Other</h4>
<br>
<table>
<thead>
<tr>
<td>{% trans %}Comments{% endtrans %}</td>
</tr>
</thead>
<tbody>
<tr>
<td>{{ shoppinglist.comment }}</td>
</tr>
</tbody>
</table>
{% endblock %}

View File

@ -28,11 +28,11 @@ Shopping list for {{ stock }}
</tr>
</thead>
<tbody>
{% for s in shoppinglist_list.filter(todo=True).filter(stock_owner=stock).order_by('-date') %}
{% for s in stock.shopping_lists.filter(todo=True).filter(stock_owner=stock).order_by('-date').all() %}
<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>{{ s.shopping_items_to_buy.count() }}</td>
<td>
<a href="{{ url('stock:update_after_shopping', stock_id=stock.id, shoppinglist_id=s.id)}}">{% trans %}Update stock{% endtrans %}</a>
</td>
@ -57,11 +57,11 @@ Shopping list for {{ stock }}
</tr>
</thead>
<tbody>
{% for s in shoppinglist_list.filter(todo=False).filter(stock_owner=stock).order_by('-date') %}
{% for s in stock.shopping_lists.filter(todo=False).filter(stock_owner=stock).order_by('-date').all() %}
<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>{{ s.shopping_items_to_buy.count() }}</td>
<td>
<a href="{{ url('stock:shoppinglist_set_todo', stock_id=stock.id, shoppinglist_id=s.id)}}">{% trans %}Mark as to do{% endtrans %}</a>
</td>

View File

@ -1,16 +1,21 @@
from collections import OrderedDict
from datetime import datetime, timedelta
from django.utils import timezone
from django.shortcuts import render, get_object_or_404
from django.views.generic import ListView, DetailView, RedirectView, TemplateView
from django.views.generic.edit import UpdateView, CreateView, DeleteView, ProcessFormView, FormMixin
from django.views.generic.edit import UpdateView, CreateView, DeleteView, ProcessFormView, FormMixin, BaseFormView
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
from django.db import transaction, DataError
from core.views import CanViewMixin, CanEditMixin, CanEditPropMixin, CanCreateMixin, TabedViewMixin
from counter.views import CounterAdminTabsMixin, CounterTabsMixin
from counter.models import Counter, ProductType
from stock.models import Stock, StockItem, ShoppingList
from stock.models import Stock, StockItem, ShoppingList, ShoppingListItem
class StockItemList(CounterAdminTabsMixin, CanCreateMixin, ListView):
@ -76,7 +81,7 @@ class StockItemEditView(CounterAdminTabsMixin, CanEditPropMixin, UpdateView):
An edit view for a stock item
"""
model = StockItem
form_class = modelform_factory(StockItem, fields=['name', 'unit_quantity', 'effective_quantity', 'type', 'stock_owner'])
form_class = modelform_factory(StockItem, fields=['name', 'unit_quantity', 'effective_quantity', 'minimal_quantity', 'type', 'stock_owner'])
pk_url_kwarg = "item_id"
template_name = 'core/edit.jinja'
current_tab = "stocks"
@ -104,7 +109,7 @@ class StockItemCreateView(CounterAdminTabsMixin, CanCreateMixin, CreateView):
A create view for a new StockItem
"""
model = StockItem
form_class = modelform_factory(StockItem, fields=['name', 'unit_quantity', 'effective_quantity', 'type', 'stock_owner'])
form_class = modelform_factory(StockItem, fields=['name', 'unit_quantity', 'effective_quantity', 'minimal_quantity', 'type', 'stock_owner'])
template_name = 'core/create.jinja'
pk_url_kwarg = "stock_id"
current_tab = "stocks"
@ -144,13 +149,21 @@ class StockItemQuantityForm(forms.BaseForm):
shopping_list.stock_owner = self.stock
shopping_list.save()
for k,t in self.cleaned_data.items():
if int(t) > 0 :
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()
if k == 'name':
shopping_list.name = t
shopping_list.save()
elif k == "comment":
shopping_list.comment = t
shopping_list.save()
else:
if t > 0 :
item_id = int(k[5:])
item = StockItem.objects.filter(id=item_id).first()
shoppinglist_item = ShoppingListItem(stockitem_owner=item, name=item.name, type=item.type, tobuy_quantity=t)
shoppinglist_item.save()
shoppinglist_item.shopping_lists.add(shopping_list)
shoppinglist_item.save()
return self.cleaned_data
class StockItemQuantityBaseFormView(CounterAdminTabsMixin, CanEditMixin, DetailView, BaseFormView):
@ -165,13 +178,15 @@ class StockItemQuantityBaseFormView(CounterAdminTabsMixin, CanEditMixin, DetailV
def get_form_class(self):
fields = OrderedDict()
kwargs = {}
fields['name'] = forms.CharField(max_length=30, required=True, label='Shopping list name')
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),
fields[field_name] = forms.IntegerField(required=True, label=str(i),
help_text=str(i.effective_quantity)+" left")
kwargs[field_name] = i.effective_quantity
fields['comment'] = forms.CharField(widget=forms.Textarea(), required=False,
initial="Add here, items to buy that are not reference as a product (example : sponge, knife, mugs ...)")
kwargs['stock_id'] = self.stock.id
kwargs['base_fields'] = fields
return type('StockItemQuantityForm', (StockItemQuantityForm,), kwargs)
@ -272,11 +287,18 @@ class StockUpdateAfterShopppingForm(forms.BaseForm):
with transaction.atomic():
self.shoppinglist = ShoppingList.objects.filter(id=self.shoppinglist_id).first()
for k,t in self.cleaned_data.items():
item_id = int(k[5:])
shoppinglist_item_id = int(k[5:])
#item_id = int(k[5:])
if int(t) > 0 :
item = StockItem.objects.filter(id=item_id).first()
item.effective_quantity += int(t)
item.save()
shoppinglist_item = ShoppingListItem.objects.filter(id=shoppinglist_item_id).first()
shoppinglist_item.bought_quantity = int(t)
shoppinglist_item.save()
shoppinglist_item.stockitem_owner.effective_quantity += int(t)
shoppinglist_item.stockitem_owner.save()
#item = StockItem.objects.filter(id=item_id).first()
#item.bought_quantity = int(t)
#item.effective_quantity += int(t)
#item.save()
self.shoppinglist.todo = False
self.shoppinglist.save()
return self.cleaned_data
@ -294,7 +316,7 @@ class StockUpdateAfterShopppingBaseFormView(CounterAdminTabsMixin, CanEditMixin,
fields = OrderedDict()
kwargs = {}
for t in ProductType.objects.order_by('name').all():
for i in self.shoppinglist.items_to_buy.filter(type=t).order_by('name').all():
for i in self.shoppinglist.shopping_items_to_buy.filter(type=t).order_by('name').all():
field_name = "item-%s" % (str(i.id))
fields[field_name] = forms.CharField(max_length=30, required=True, label=str(i),
help_text=str(i.tobuy_quantity) + " asked")
@ -341,9 +363,9 @@ class StockTakeItemsForm(forms.BaseForm):
with transaction.atomic():
for k,t in self.cleaned_data.items():
item_id = int(k[5:])
if int(t) > 0 :
if t > 0 :
item = StockItem.objects.filter(id=item_id).first()
item.effective_quantity -= int(t)
item.effective_quantity -= t
item.save()
return self.cleaned_data
@ -363,7 +385,7 @@ class StockTakeItemsBaseFormView(CounterTabsMixin, CanEditMixin, DetailView, Bas
for t in ProductType.objects.order_by('name').all():
for i in self.stock.items.filter(type=t).order_by('name').all():
field_name = "item-%s" % (str(i.id))
fields[field_name] = forms.CharField(max_length=30, required=True, label=str(i))
fields[field_name] = forms.IntegerField(required=False, label=str(i), help_text="("+ str(i.effective_quantity) + " left)")
kwargs[field_name] = i.effective_quantity
kwargs['stock_id'] = self.stock.id
kwargs['counter_id'] = self.stock.counter.id