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, 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, ShoppingListItem class StockItemList(CounterAdminTabsMixin, CanCreateMixin, ListView): """ The stockitems list view for the counter owner """ model = Stock template_name = 'stock/stock_item_list.jinja' pk_url_kwarg = "stock_id" current_tab = "stocks" def get_context_data(self): ret = super(StockItemList, self).get_context_data() if 'stock_id' in self.kwargs.keys(): ret['stock'] = Stock.objects.filter(id=self.kwargs['stock_id']).first(); return ret class StockListView(CounterAdminTabsMixin, CanViewMixin, ListView): """ A list view for the admins """ model = Stock template_name = 'stock/stock_list.jinja' current_tab = "stocks" class StockEditForm(forms.ModelForm): """ A form to change stock's characteristics """ class Meta: model = Stock fields = ['name', 'counter'] def __init__(self, *args, **kwargs): super(StockEditForm, self).__init__(*args, **kwargs) def save(self, *args, **kwargs): return super(StockEditForm, self).save(*args, **kwargs) class StockEditView(CounterAdminTabsMixin, CanEditPropMixin, UpdateView): """ An edit view for the stock """ model = Stock form_class = modelform_factory(Stock, fields=['name', 'counter']) pk_url_kwarg = "stock_id" template_name = 'core/edit.jinja' current_tab = "stocks" 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', 'minimal_quantity', 'type', 'stock_owner']) pk_url_kwarg = "item_id" template_name = 'core/edit.jinja' current_tab = "stocks" class StockCreateView(CounterAdminTabsMixin, CanCreateMixin, CreateView): """ A create view for a new Stock """ model = Stock form_class = modelform_factory(Stock, fields=['name', 'counter']) template_name = 'core/create.jinja' pk_url_kwarg = "counter_id" current_tab = "stocks" success_url = reverse_lazy('stock:list') def get_initial(self): ret = super(StockCreateView, self).get_initial() if 'counter_id' in self.kwargs.keys(): ret['counter'] = self.kwargs['counter_id'] return ret 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', 'minimal_quantity', 'type', 'stock_owner']) template_name = 'core/create.jinja' pk_url_kwarg = "stock_id" current_tab = "stocks" def get_initial(self): ret = super(StockItemCreateView, self).get_initial() if 'stock_id' in self.kwargs.keys(): ret['stock_owner'] = self.kwargs['stock_id'] return ret def get_success_url(self): return reverse_lazy('stock:items_list', kwargs={'stock_id':self.object.stock_owner.id}) class StockShoppingListView(CounterAdminTabsMixin, CanViewMixin, ListView): """ A list view for the people to know the item to buy """ model = Stock template_name = "stock/stock_shopping_list.jinja" pk_url_kwarg = "stock_id" current_tab = "stocks" def get_context_data(self): ret = super(StockShoppingListView, self).get_context_data() if 'stock_id' in self.kwargs.keys(): ret['stock'] = Stock.objects.filter(id=self.kwargs['stock_id']).first(); return ret 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 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): """ 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 = {} 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.IntegerField(required=True, label=str(i), initial=0, help_text=_(str(i.effective_quantity)+" left")) fields['comment'] = forms.CharField(widget=forms.Textarea(attrs={"placeholder":_("Add here, items to buy that are not reference as a stock item (example : sponge, knife, mugs ...)")}), required=False, label=_("Comments")) 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): return super(StockItemQuantityBaseFormView, self).form_valid(form) def get_context_data(self, **kwargs): 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})) class StockUpdateAfterShopppingForm(forms.BaseForm): def clean(self): with transaction.atomic(): self.shoppinglist = ShoppingList.objects.filter(id=self.shoppinglist_id).first() for k,t in self.cleaned_data.items(): shoppinglist_item_id = int(k[5:]) if int(t) > 0 : 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() self.shoppinglist.todo = False self.shoppinglist.save() return self.cleaned_data class StockUpdateAfterShopppingBaseFormView(CounterAdminTabsMixin, CanEditMixin, DetailView, BaseFormView): """ docstring for StockUpdateAfterShopppingBaseFormView """ model = ShoppingList template_name = "stock/update_after_shopping.jinja" pk_url_kwarg = "shoppinglist_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.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")) kwargs['shoppinglist_id'] = self.shoppinglist.id kwargs['base_fields'] = fields return type('StockUpdateAfterShopppingForm', (StockUpdateAfterShopppingForm,), kwargs) def get(self, request, *args, **kwargs): self.shoppinglist = ShoppingList.objects.filter(id=self.kwargs['shoppinglist_id']).first() return super(StockUpdateAfterShopppingBaseFormView, 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.shoppinglist = ShoppingList.objects.filter(id=self.kwargs['shoppinglist_id']).first() return super(StockUpdateAfterShopppingBaseFormView, self).post(request, *args, **kwargs) def form_valid(self, form): """ We handle here the redirection """ return super(StockUpdateAfterShopppingBaseFormView, self).form_valid(form) def get_context_data(self, **kwargs): kwargs = super(StockUpdateAfterShopppingBaseFormView, self).get_context_data(**kwargs) if 'form' not in kwargs.keys(): kwargs['form'] = self.get_form() kwargs['shoppinglist'] = self.shoppinglist kwargs['stock'] = self.shoppinglist.stock_owner return kwargs def get_success_url(self): self.kwargs.pop('shoppinglist_id', None) return reverse_lazy('stock:shoppinglist_list', args=self.args, kwargs=self.kwargs) class StockTakeItemsForm(forms.BaseForm): """ docstring for StockTakeItemsFormView """ def clean(self): with transaction.atomic(): for k,t in self.cleaned_data.items(): item_id = int(k[5:]) if t > 0 : item = StockItem.objects.filter(id=item_id).first() item.effective_quantity -= t item.save() return self.cleaned_data class StockTakeItemsBaseFormView(CounterTabsMixin, CanEditMixin, DetailView, BaseFormView): """ docstring for StockTakeItemsBaseFormView """ model = StockItem template_name = "stock/stock_take_items.jinja" pk_url_kwarg = "stock_id" current_tab = "take_items_from_stock" 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(): field_name = "item-%s" % (str(i.id)) fields[field_name] = forms.IntegerField(required=False, label=str(i), initial=0, min_value=0, max_value=i.effective_quantity, help_text=_("(%(effective_quantity)s left" % {"effective_quantity": str(i.effective_quantity)})) kwargs[field_name] = i.effective_quantity kwargs['stock_id'] = self.stock.id kwargs['counter_id'] = self.stock.counter.id kwargs['base_fields'] = fields return type('StockTakeItemsForm', (StockTakeItemsForm,), kwargs) def get(self, request, *args, **kwargs): """ Simple get view """ self.stock = Stock.objects.filter(id=self.kwargs['stock_id']).first() return super(StockTakeItemsBaseFormView, 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() if self.stock.counter.type == "BAR" and not ('counter_token' in self.request.session.keys() and self.request.session['counter_token'] == self.stock.counter.token): # Also check the token to avoid the bar to be stolen return HttpResponseRedirect(reverse_lazy('counter:details', args=self.args, kwargs={'counter_id': self.stock.counter.id})+'?bad_location') return super(StockTakeItemsBaseFormView, self).post(request, *args, **kwargs) def form_valid(self, form): return super(StockTakeItemsBaseFormView, self).form_valid(form) def get_context_data(self, **kwargs): kwargs = super(StockTakeItemsBaseFormView, self).get_context_data(**kwargs) if 'form' not in kwargs.keys(): kwargs['form'] = self.get_form() kwargs['stock'] = self.stock kwargs['counter'] = self.stock.counter return kwargs def get_success_url(self): stock = Stock.objects.filter(id=self.kwargs['stock_id']).first() self.kwargs['counter_id'] = stock.counter.id self.kwargs.pop('stock_id', None) return reverse_lazy('counter:details', args=self.args, kwargs=self.kwargs)