forked from DGNum/gestioCOF
Inventaire depuis une commande
- Possible de générer un inventaire à partir d'une commande passée. Préremplissage avec les valeurs commandées. - Possible d'indiquer les prix d'achat pour avoir l'historique des prix d'un article chez un fournisseur. Et bientôt, une proposition automatique de prix. - L'erreur sur le stock d'un article lors d'un inventaire n'est pas mise à jour dans le cas où l'inventaire est généré à partir d'une commande. - Ajout d'un champ `at` au modèle `SupplierArticle` afin de conserver l'historique des prix d'achat - Fix sur la vue `order_create`
This commit is contained in:
parent
61feb9bbcd
commit
9467103879
9 changed files with 218 additions and 7 deletions
|
@ -447,3 +447,27 @@ class OrderArticleForm(forms.Form):
|
|||
self.v_et = kwargs['initial']['v_et']
|
||||
self.v_prev = kwargs['initial']['v_prev']
|
||||
self.c_rec = kwargs['initial']['c_rec']
|
||||
|
||||
class OrderArticleToInventoryForm(forms.Form):
|
||||
article = forms.ModelChoiceField(
|
||||
queryset = Article.objects.all(),
|
||||
widget = forms.HiddenInput(),
|
||||
)
|
||||
price_HT = forms.DecimalField(
|
||||
max_digits = 7, decimal_places = 4,
|
||||
required = False)
|
||||
TVA = forms.DecimalField(
|
||||
max_digits = 7, decimal_places = 2,
|
||||
required = False)
|
||||
rights = forms.DecimalField(
|
||||
max_digits = 7, decimal_places = 4,
|
||||
required = False)
|
||||
quantity_received = forms.IntegerField()
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
super(OrderArticleToInventoryForm, self).__init__(*args, **kwargs)
|
||||
if 'initial' in kwargs:
|
||||
self.name = kwargs['initial']['name']
|
||||
self.category = kwargs['initial']['category']
|
||||
self.category_name = kwargs['initial']['category__name']
|
||||
self.quantity_ordered = kwargs['initial']['quantity_ordered']
|
||||
|
|
31
kfet/migrations/0040_auto_20160829_2035.py
Normal file
31
kfet/migrations/0040_auto_20160829_2035.py
Normal file
|
@ -0,0 +1,31 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
from __future__ import unicode_literals
|
||||
|
||||
from django.db import models, migrations
|
||||
import datetime
|
||||
from django.utils.timezone import utc
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('kfet', '0039_auto_20160828_0430'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AlterModelOptions(
|
||||
name='order',
|
||||
options={'ordering': ['-at']},
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='supplierarticle',
|
||||
name='at',
|
||||
field=models.DateTimeField(auto_now_add=True, default=datetime.datetime(2016, 8, 29, 18, 35, 3, 419033, tzinfo=utc)),
|
||||
preserve_default=False,
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='article',
|
||||
name='box_type',
|
||||
field=models.CharField(choices=[('caisse', 'caisse'), ('carton', 'carton'), ('palette', 'palette'), ('fût', 'fût')], null=True, max_length=7, blank=True, default=None),
|
||||
),
|
||||
]
|
18
kfet/migrations/0041_auto_20160830_1502.py
Normal file
18
kfet/migrations/0041_auto_20160830_1502.py
Normal file
|
@ -0,0 +1,18 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
from __future__ import unicode_literals
|
||||
|
||||
from django.db import models, migrations
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('kfet', '0040_auto_20160829_2035'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AlterModelOptions(
|
||||
name='globalpermissions',
|
||||
options={'permissions': (('is_team', 'Is part of the team'), ('perform_deposit', 'Effectuer une charge'), ('perform_negative_operations', 'Enregistrer des commandes en négatif'), ('override_frozen_protection', "Forcer le gel d'un compte"), ('cancel_old_operations', 'Annuler des commandes non récentes'), ('manage_perms', 'Gérer les permissions K-Fêt'), ('manage_addcosts', 'Gérer les majorations'), ('perform_commented_operations', 'Enregistrer des commandes avec commentaires'), ('view_negs', 'Voir la liste des négatifs'), ('order_to_inventory', "Générer un inventaire à partir d'une commande")), 'managed': False},
|
||||
),
|
||||
]
|
|
@ -381,7 +381,10 @@ class InventoryArticle(models.Model):
|
|||
stock_error = models.IntegerField(default = 0)
|
||||
|
||||
def save(self, *args, **kwargs):
|
||||
self.stock_error = self.stock_new - self.stock_old
|
||||
# S'il s'agit d'un inventaire provenant d'une livraison, il n'y a pas
|
||||
# d'erreur
|
||||
if not hasattr(self.inventory, 'order'):
|
||||
self.stock_error = self.stock_new - self.stock_old
|
||||
super(InventoryArticle, self).save(*args, **kwargs)
|
||||
|
||||
class Supplier(models.Model):
|
||||
|
@ -403,6 +406,7 @@ class SupplierArticle(models.Model):
|
|||
Supplier, on_delete = models.PROTECT)
|
||||
article = models.ForeignKey(
|
||||
Article, on_delete = models.PROTECT)
|
||||
at = models.DateTimeField(auto_now_add = True)
|
||||
price_HT = models.DecimalField(
|
||||
max_digits = 7, decimal_places = 4,
|
||||
blank = True, null = True, default = None)
|
||||
|
@ -543,6 +547,7 @@ class GlobalPermissions(models.Model):
|
|||
('manage_addcosts', 'Gérer les majorations'),
|
||||
('perform_commented_operations', 'Enregistrer des commandes avec commentaires'),
|
||||
('view_negs', 'Voir la liste des négatifs'),
|
||||
('order_to_inventory', "Générer un inventaire à partir d'une commande")
|
||||
)
|
||||
|
||||
class Settings(models.Model):
|
||||
|
|
|
@ -35,6 +35,7 @@
|
|||
<li><a href="{% url 'kfet.checkout' %}">Caisses</a></li>
|
||||
<li><a href="{% url 'kfet.article' %}">Articles</a></li>
|
||||
<li><a href="{% url 'kfet.history' %}">Historique</a></li>
|
||||
<li><a href="{% url 'kfet.order' %}">Commandes</a></li>
|
||||
{% if user.username != 'kfet_genericteam' %}
|
||||
<li><a href="{% url 'kfet.login.genericteam' %}" target="_blank" id="genericteam">Connexion standard</a></li>
|
||||
{% endif %}
|
||||
|
|
|
@ -66,6 +66,14 @@
|
|||
</a>
|
||||
</td>
|
||||
<td>{{ order.supplier }}</td>
|
||||
<td>
|
||||
{% if order.inventory %}
|
||||
<a href="">Inventaire associé</a>
|
||||
{% else %}
|
||||
<a href="{% url 'kfet.order.to_inventory' order.pk %}">
|
||||
Maj stock
|
||||
</a>
|
||||
{% endif %}
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</table>
|
||||
|
|
48
kfet/templates/kfet/order_to_inventory.html
Normal file
48
kfet/templates/kfet/order_to_inventory.html
Normal file
|
@ -0,0 +1,48 @@
|
|||
{% extends 'kfet/base.html' %}
|
||||
|
||||
{% block title %}{% endblock %}
|
||||
{% block content-header-title %}{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
|
||||
{% include 'kfet/base_messages.html' %}
|
||||
|
||||
<form action="" method="post">
|
||||
{% csrf_token %}
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<td>Article</td>
|
||||
<td>HT</td>
|
||||
<td>TVA</td>
|
||||
<td>Droits</td>
|
||||
<td>Com.</td>
|
||||
<td>Reçu</td>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{% for form in formset %}
|
||||
{% ifchanged form.category %}
|
||||
<tr>
|
||||
<td colspan="6">{{ form.category_name }}</td>
|
||||
</tr>
|
||||
{% endifchanged %}
|
||||
<tr>
|
||||
{{ form.article }}
|
||||
<td>{{ form.name }}</td>
|
||||
<td>{{ form.price_HT }}</td>
|
||||
<td>{{ form.TVA }}</td>
|
||||
<td>{{ form.rights }}</td>
|
||||
<td>{{ form.quantity_ordered }}</td>
|
||||
<td>{{ form.quantity_received }}</td>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
</table>
|
||||
{% if not perms.kfet.order_to_inventory %}
|
||||
<input type="password" name="KFETPASSWORD">
|
||||
{% endif %}
|
||||
{{ formset.management_form }}
|
||||
<input type="submit" value="Enregistrer">
|
||||
</form>
|
||||
|
||||
{% endblock %}
|
|
@ -179,7 +179,7 @@ urlpatterns = [
|
|||
url(r'^orders/$',
|
||||
permission_required('kfet.is_team')(views.OrderList.as_view()),
|
||||
name = 'kfet.order'),
|
||||
url(r'^orders/(?P<pk>\d+)',
|
||||
url(r'^orders/(?P<pk>\d+)$',
|
||||
permission_required('kfet.is_team')(views.OrderRead.as_view()),
|
||||
name = 'kfet.order.read'),
|
||||
url(r'^orders/suppliers/(?P<pk>\d+)/edit$',
|
||||
|
@ -187,4 +187,6 @@ urlpatterns = [
|
|||
name = 'kfet.order.supplier.update'),
|
||||
url(r'^orders/suppliers/(?P<pk>\d+)/new-order$', views.order_create,
|
||||
name = 'kfet.order.new'),
|
||||
url(r'^orders/(?P<pk>\d+)/to_inventory$', views.order_to_inventory,
|
||||
name = 'kfet.order.to_inventory'),
|
||||
]
|
||||
|
|
|
@ -1367,15 +1367,13 @@ class OrderList(ListView):
|
|||
|
||||
@permission_required('kfet.is_team')
|
||||
def order_create(request, pk):
|
||||
supplier = Supplier.objects.get(pk=pk)
|
||||
supplier = get_object_or_404(Supplier, pk=pk)
|
||||
|
||||
articles = (Article.objects
|
||||
.filter(suppliers=supplier.pk)
|
||||
.select_related('category')
|
||||
.order_by('category__name', 'name'))
|
||||
|
||||
print(articles[0].suppliers.all())
|
||||
|
||||
initial = []
|
||||
today = timezone.now().date()
|
||||
sales_q = (Operation.objects
|
||||
|
@ -1429,7 +1427,7 @@ def order_create(request, pk):
|
|||
v_prev = v_moy + v_et
|
||||
c_rec_tot = max(v_prev * 1.5 - article.stock, 0)
|
||||
if article.box_capacity:
|
||||
c_rec_temp = c_rec_tot / box_capacity
|
||||
c_rec_temp = c_rec_tot / article.box_capacity
|
||||
if c_rec_temp >= 10:
|
||||
c_rec = round(c_rec_temp)
|
||||
elif c_rec_temp > 5:
|
||||
|
@ -1478,7 +1476,7 @@ def order_create(request, pk):
|
|||
article = articles.get(pk=form.cleaned_data['article'].pk)
|
||||
q_ordered = form.cleaned_data['quantity_ordered']
|
||||
if article.box_capacity:
|
||||
q_ordered /= article.box_capacity
|
||||
q_ordered *= article.box_capacity
|
||||
OrderArticle.objects.create(
|
||||
order = order,
|
||||
article = article,
|
||||
|
@ -1534,6 +1532,82 @@ class OrderRead(DetailView):
|
|||
context['mail'] = mail
|
||||
return context
|
||||
|
||||
def order_to_inventory(request, pk):
|
||||
order = get_object_or_404(Order, pk=pk)
|
||||
|
||||
if hasattr(order, 'inventory'):
|
||||
raise Http404
|
||||
|
||||
articles = (Article.objects
|
||||
.filter(orders=order.pk)
|
||||
.select_related('category')
|
||||
.prefetch_related(Prefetch('orderarticle_set',
|
||||
queryset = OrderArticle.objects.filter(order=order),
|
||||
to_attr = 'order'))
|
||||
.prefetch_related(Prefetch('supplierarticle_set',
|
||||
queryset = (SupplierArticle.objects
|
||||
.filter(supplier=order.supplier)
|
||||
.order_by('-at')),
|
||||
to_attr = 'supplier'))
|
||||
.order_by('category__name', 'name'))
|
||||
|
||||
initial = []
|
||||
for article in articles:
|
||||
initial.append({
|
||||
'article': article.pk,
|
||||
'name': article.name,
|
||||
'category': article.category_id,
|
||||
'category__name': article.category.name,
|
||||
'quantity_ordered': article.order[0].quantity_ordered,
|
||||
'quantity_received': article.order[0].quantity_ordered,
|
||||
'price_HT': article.supplier[0].price_HT,
|
||||
'TVA': article.supplier[0].TVA,
|
||||
'rights': article.supplier[0].rights,
|
||||
})
|
||||
|
||||
cls_formset = formset_factory(OrderArticleToInventoryForm, extra=0)
|
||||
|
||||
if request.method == 'POST':
|
||||
formset = cls_formset(request.POST, initial=initial)
|
||||
|
||||
if not request.user.has_perm('kfet.order_to_inventory'):
|
||||
message.error(request, 'Permission refusée')
|
||||
elif formset.is_valid():
|
||||
with transaction.atomic():
|
||||
inventory = Inventory()
|
||||
inventory.order = order
|
||||
inventory.by = request.user.profile.account_kfet
|
||||
inventory.save()
|
||||
for form in formset:
|
||||
q_received = form.cleaned_data['quantity_received']
|
||||
article = form.cleaned_data['article']
|
||||
SupplierArticle.objects.create(
|
||||
supplier = order.supplier,
|
||||
article = article,
|
||||
price_HT = form.cleaned_data['price_HT'],
|
||||
TVA = form.cleaned_data['TVA'],
|
||||
rights = form.cleaned_data['rights'])
|
||||
(OrderArticle.objects
|
||||
.filter(order=order, article=article)
|
||||
.update(quantity_received = q_received))
|
||||
InventoryArticle.objects.create(
|
||||
inventory = inventory,
|
||||
article = article,
|
||||
stock_old = article.stock,
|
||||
stock_new = article.stock + q_received)
|
||||
article.stock += q_received
|
||||
article.save()
|
||||
messages.success(request, "C'est tout bon !")
|
||||
return redirect('kfet.order')
|
||||
else:
|
||||
messages.error(request, "Corrigez les erreurs")
|
||||
else:
|
||||
formset = cls_formset(initial=initial)
|
||||
|
||||
return render(request, 'kfet/order_to_inventory.html', {
|
||||
'formset': formset,
|
||||
})
|
||||
|
||||
class SupplierUpdate(SuccessMessageMixin, UpdateView):
|
||||
model = Supplier
|
||||
template_name = 'kfet/supplier_form.html'
|
||||
|
|
Loading…
Reference in a new issue