forked from DGNum/gestioCOF
Ajout du listing et création d'inventaires
This commit is contained in:
parent
cd436faf9b
commit
ffa73c41c3
7 changed files with 203 additions and 5 deletions
|
@ -8,7 +8,7 @@ from django.forms.models import BaseInlineFormSet
|
||||||
from django.utils import timezone
|
from django.utils import timezone
|
||||||
from kfet.models import (Account, Checkout, Article, OperationGroup, Operation,
|
from kfet.models import (Account, Checkout, Article, OperationGroup, Operation,
|
||||||
CheckoutStatement, ArticleCategory, Settings, AccountNegative, Transfer,
|
CheckoutStatement, ArticleCategory, Settings, AccountNegative, Transfer,
|
||||||
TransferGroup, Supplier)
|
TransferGroup, Supplier, Inventory, InventoryArticle)
|
||||||
from gestioncof.models import CofProfile
|
from gestioncof.models import CofProfile
|
||||||
|
|
||||||
# -----
|
# -----
|
||||||
|
@ -397,3 +397,22 @@ TransferFormSet = modelformset_factory(
|
||||||
min_num = 1, validate_min = True,
|
min_num = 1, validate_min = True,
|
||||||
extra = 9,
|
extra = 9,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
# -----
|
||||||
|
# Inventory forms
|
||||||
|
# -----
|
||||||
|
|
||||||
|
class InventoryArticleForm(forms.Form):
|
||||||
|
article = forms.ModelChoiceField(
|
||||||
|
queryset = Article.objects.all(),
|
||||||
|
widget = forms.HiddenInput(),
|
||||||
|
)
|
||||||
|
stock_new = forms.IntegerField(required = False)
|
||||||
|
|
||||||
|
def __init__(self, *args, **kwargs):
|
||||||
|
super(InventoryArticleForm, self).__init__(*args, **kwargs)
|
||||||
|
if 'initial' in kwargs:
|
||||||
|
self.name = kwargs['initial']['name']
|
||||||
|
self.stock_old = kwargs['initial']['stock_old']
|
||||||
|
self.category = kwargs['initial']['category']
|
||||||
|
self.category_name = kwargs['initial']['category__name']
|
||||||
|
|
|
@ -356,6 +356,9 @@ class Inventory(models.Model):
|
||||||
related_name = "inventory",
|
related_name = "inventory",
|
||||||
blank = True, null = True, default = None)
|
blank = True, null = True, default = None)
|
||||||
|
|
||||||
|
class Meta:
|
||||||
|
ordering = ['-at']
|
||||||
|
|
||||||
class InventoryArticle(models.Model):
|
class InventoryArticle(models.Model):
|
||||||
inventory = models.ForeignKey(
|
inventory = models.ForeignKey(
|
||||||
Inventory, on_delete = models.PROTECT)
|
Inventory, on_delete = models.PROTECT)
|
||||||
|
|
|
@ -145,3 +145,9 @@ a:focus, a:hover {
|
||||||
.content-right-block table {
|
.content-right-block table {
|
||||||
width:100%;
|
width:100%;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.content-right-block table thead {
|
||||||
|
background:#c8102e;
|
||||||
|
color:#fff;
|
||||||
|
font-weight:bold;
|
||||||
|
}
|
||||||
|
|
52
kfet/templates/kfet/inventory.html
Normal file
52
kfet/templates/kfet/inventory.html
Normal file
|
@ -0,0 +1,52 @@
|
||||||
|
{% extends 'kfet/base.html' %}
|
||||||
|
|
||||||
|
{% block title %}Inventaires{% endblock %}
|
||||||
|
{% block content-header-title %}Inventaires{% endblock %}
|
||||||
|
|
||||||
|
{% block content %}
|
||||||
|
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-sm-4 col-md-3 col-content-left">
|
||||||
|
<div class="content-left">
|
||||||
|
<div class="content-left-top">
|
||||||
|
</div>
|
||||||
|
<div class="buttons">
|
||||||
|
<a href="{% url 'kfet.inventory.create' %}" class="btn btn-primary btn-lg">
|
||||||
|
Nouveau
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="col-sm-8 col-md-9 col-content-right">
|
||||||
|
{% include 'kfet/base_messages.html' %}
|
||||||
|
<div class="content-right">
|
||||||
|
<div class="content-right-block">
|
||||||
|
<h2>Liste des inventaires</h2>
|
||||||
|
<div>
|
||||||
|
<table class="table">
|
||||||
|
<thead class="thead-default">
|
||||||
|
<tr>
|
||||||
|
<td>Date/Heure</td>
|
||||||
|
<td>Par</td>
|
||||||
|
<td>Nb articles</td>
|
||||||
|
<td>Commande</td>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
{% for inventory in inventories %}
|
||||||
|
<tr>
|
||||||
|
<td>{{ inventory.at }}</td>
|
||||||
|
<td>{{ inventory.by.trigramme }}</td>
|
||||||
|
<td>{{ inventory.nb_articles }}</td>
|
||||||
|
<td>{{ inventory.order|default_if_none:'' }}</td>
|
||||||
|
</tr>
|
||||||
|
{% endfor %}
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{% endblock %}
|
41
kfet/templates/kfet/inventory_create.html
Normal file
41
kfet/templates/kfet/inventory_create.html
Normal file
|
@ -0,0 +1,41 @@
|
||||||
|
{% extends 'kfet/base.html' %}
|
||||||
|
|
||||||
|
{% block title %}Nouvel inventaire{% endblock %}
|
||||||
|
{% block content-header-title %}Nouvel inventaire{% endblock %}
|
||||||
|
|
||||||
|
{% block content %}
|
||||||
|
|
||||||
|
<form action="" method="post">
|
||||||
|
<table>
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<td>Article</td>
|
||||||
|
<td>Théo.</td>
|
||||||
|
<td>Réel</td>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
{% for form in formset %}
|
||||||
|
{% ifchanged form.category %}
|
||||||
|
<tr>
|
||||||
|
<td colspan="3">{{ form.category_name }}</td>
|
||||||
|
</tr>
|
||||||
|
{% endifchanged %}
|
||||||
|
<tr>
|
||||||
|
{{ form.article }}
|
||||||
|
<td>{{ form.name }}</td>
|
||||||
|
<td>{{ form.stock_old }}</td>
|
||||||
|
<td>{{ form.stock_new }}</td>
|
||||||
|
</tr>
|
||||||
|
{% endfor %}
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
{% if not perms.kfet.add_inventory %}
|
||||||
|
<input type="password" name="KFETPASSWORD">
|
||||||
|
{% endif %}
|
||||||
|
{% csrf_token %}
|
||||||
|
{{ formset.management_form }}
|
||||||
|
<input type="submit" value="Enregistrer" class="btn btn-primary btn-lg">
|
||||||
|
</form>
|
||||||
|
|
||||||
|
{% endblock %}
|
|
@ -161,4 +161,13 @@ urlpatterns = [
|
||||||
name = 'kfet.transfers.create'),
|
name = 'kfet.transfers.create'),
|
||||||
url(r'^transfers/perform$', views.perform_transfers,
|
url(r'^transfers/perform$', views.perform_transfers,
|
||||||
name = 'kfet.transfers.perform'),
|
name = 'kfet.transfers.perform'),
|
||||||
|
|
||||||
|
# -----
|
||||||
|
# Inventories urls
|
||||||
|
|
||||||
|
url(r'^inventaires/$',
|
||||||
|
permission_required('kfet.is_team')(views.InventoryList.as_view()),
|
||||||
|
name = 'kfet.inventory'),
|
||||||
|
url(r'^inventaires/new$', views.inventory_create,
|
||||||
|
name = 'kfet.inventory.create'),
|
||||||
]
|
]
|
||||||
|
|
|
@ -2,7 +2,7 @@ from django.shortcuts import render, get_object_or_404, redirect
|
||||||
from django.core.exceptions import PermissionDenied, ValidationError
|
from django.core.exceptions import PermissionDenied, ValidationError
|
||||||
from django.core.cache import cache
|
from django.core.cache import cache
|
||||||
from django.views.generic import ListView, DetailView
|
from django.views.generic import ListView, DetailView
|
||||||
from django.views.generic.edit import CreateView, UpdateView, DeleteView
|
from django.views.generic.edit import CreateView, UpdateView, DeleteView, FormView
|
||||||
from django.core.urlresolvers import reverse_lazy
|
from django.core.urlresolvers import reverse_lazy
|
||||||
from django.contrib import messages
|
from django.contrib import messages
|
||||||
from django.contrib.messages.views import SuccessMessageMixin
|
from django.contrib.messages.views import SuccessMessageMixin
|
||||||
|
@ -10,15 +10,16 @@ from django.contrib.auth import authenticate, login
|
||||||
from django.contrib.auth.decorators import login_required, permission_required
|
from django.contrib.auth.decorators import login_required, permission_required
|
||||||
from django.contrib.auth.models import User, Permission, Group
|
from django.contrib.auth.models import User, Permission, Group
|
||||||
from django.http import HttpResponse, JsonResponse, Http404
|
from django.http import HttpResponse, JsonResponse, Http404
|
||||||
from django.forms import modelformset_factory
|
from django.forms import modelformset_factory, formset_factory
|
||||||
from django.db import IntegrityError, transaction
|
from django.db import IntegrityError, transaction
|
||||||
from django.db.models import F, Sum, Prefetch
|
from django.db.models import F, Sum, Prefetch, Count
|
||||||
from django.db.models.functions import Coalesce
|
from django.db.models.functions import Coalesce
|
||||||
from django.utils import timezone
|
from django.utils import timezone
|
||||||
from django.utils.crypto import get_random_string
|
from django.utils.crypto import get_random_string
|
||||||
from gestioncof.models import CofProfile, Clipper
|
from gestioncof.models import CofProfile, Clipper
|
||||||
from kfet.models import (Account, Checkout, Article, Settings, AccountNegative,
|
from kfet.models import (Account, Checkout, Article, Settings, AccountNegative,
|
||||||
CheckoutStatement, GenericTeamToken, Supplier, SupplierArticle)
|
CheckoutStatement, GenericTeamToken, Supplier, SupplierArticle, Inventory,
|
||||||
|
InventoryArticle)
|
||||||
from kfet.forms import *
|
from kfet.forms import *
|
||||||
from collections import defaultdict
|
from collections import defaultdict
|
||||||
from kfet import consumers
|
from kfet import consumers
|
||||||
|
@ -1257,3 +1258,70 @@ def perform_transfers(request):
|
||||||
data['transfers'].append(transfer.pk)
|
data['transfers'].append(transfer.pk)
|
||||||
|
|
||||||
return JsonResponse(data)
|
return JsonResponse(data)
|
||||||
|
|
||||||
|
class InventoryList(ListView):
|
||||||
|
queryset = (Inventory.objects
|
||||||
|
.select_related('by', 'order')
|
||||||
|
.annotate(nb_articles=Count('articles'))
|
||||||
|
.order_by('-at'))
|
||||||
|
template_name = 'kfet/inventory.html'
|
||||||
|
context_object_name = 'inventories'
|
||||||
|
|
||||||
|
@permission_required('kfet.is_team')
|
||||||
|
def inventory_create(request):
|
||||||
|
|
||||||
|
articles = (Article.objects
|
||||||
|
.select_related('category')
|
||||||
|
.order_by('category__name', 'name')
|
||||||
|
)
|
||||||
|
initial = []
|
||||||
|
data = []
|
||||||
|
for article in articles:
|
||||||
|
initial.append({
|
||||||
|
'article' : article.pk,
|
||||||
|
'stock_old': article.stock,
|
||||||
|
'name' : article.name,
|
||||||
|
'category' : article.category_id,
|
||||||
|
'category__name': article.category.name
|
||||||
|
})
|
||||||
|
|
||||||
|
cls_formset = formset_factory(
|
||||||
|
form = InventoryArticleForm,
|
||||||
|
extra = 0,
|
||||||
|
)
|
||||||
|
|
||||||
|
if request.POST:
|
||||||
|
formset = cls_formset(request.POST, initial=initial)
|
||||||
|
if formset.is_valid():
|
||||||
|
with transaction.atomic():
|
||||||
|
|
||||||
|
articles = Article.objects.select_for_update()
|
||||||
|
inventory = Inventory()
|
||||||
|
inventory.by = request.user.profile.account_kfet
|
||||||
|
saved = False
|
||||||
|
for form in formset:
|
||||||
|
if form.cleaned_data['stock_new'] is not None:
|
||||||
|
if not saved:
|
||||||
|
inventory.save()
|
||||||
|
|
||||||
|
article = articles.get(pk=form.cleaned_data['article'].pk)
|
||||||
|
stock_old = article.stock
|
||||||
|
stock_new = form.cleaned_data['stock_new']
|
||||||
|
stock_error = stock_new - stock_old
|
||||||
|
InventoryArticle.objects.create(
|
||||||
|
inventory = inventory,
|
||||||
|
article = article,
|
||||||
|
stock_old = stock_old,
|
||||||
|
stock_new = stock_new,
|
||||||
|
stock_error = stock_error)
|
||||||
|
article.stock = stock_new
|
||||||
|
article.save()
|
||||||
|
print('ok')
|
||||||
|
else:
|
||||||
|
messages.error('Pas marché')
|
||||||
|
else:
|
||||||
|
formset = cls_formset(initial = initial)
|
||||||
|
|
||||||
|
return render(request, 'kfet/inventory_create.html', {
|
||||||
|
'formset': formset,
|
||||||
|
})
|
||||||
|
|
Loading…
Reference in a new issue