forked from DGNum/gestioCOF
Ajout livraison
- Possible de passer une livraison à un fournisseur - Proposition de quantités générées à partir des ventes sur les 5 dernières semaines - Mail généré à partir d'une commande (pas d'envoi auto) - box_capacity et box_type passe de SupplierArticle à Article
This commit is contained in:
parent
d531c7dd5b
commit
61feb9bbcd
9 changed files with 391 additions and 28 deletions
|
@ -218,11 +218,13 @@ class ArticleForm(forms.ModelForm):
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
model = Article
|
model = Article
|
||||||
fields = ['name', 'is_sold', 'price', 'stock', 'category']
|
fields = ['name', 'is_sold', 'price', 'stock', 'category', 'box_type',
|
||||||
|
'box_capacity']
|
||||||
|
|
||||||
class ArticleRestrictForm(ArticleForm):
|
class ArticleRestrictForm(ArticleForm):
|
||||||
class Meta(ArticleForm.Meta):
|
class Meta(ArticleForm.Meta):
|
||||||
fields = ['name', 'is_sold', 'price', 'category']
|
fields = ['name', 'is_sold', 'price', 'category', 'box_type',
|
||||||
|
'box_capacity']
|
||||||
|
|
||||||
# -----
|
# -----
|
||||||
# K-Psul forms
|
# K-Psul forms
|
||||||
|
@ -416,3 +418,32 @@ class InventoryArticleForm(forms.Form):
|
||||||
self.stock_old = kwargs['initial']['stock_old']
|
self.stock_old = kwargs['initial']['stock_old']
|
||||||
self.category = kwargs['initial']['category']
|
self.category = kwargs['initial']['category']
|
||||||
self.category_name = kwargs['initial']['category__name']
|
self.category_name = kwargs['initial']['category__name']
|
||||||
|
|
||||||
|
# -----
|
||||||
|
# Order forms
|
||||||
|
# -----
|
||||||
|
|
||||||
|
class OrderArticleForm(forms.Form):
|
||||||
|
article = forms.ModelChoiceField(
|
||||||
|
queryset = Article.objects.all(),
|
||||||
|
widget = forms.HiddenInput(),
|
||||||
|
)
|
||||||
|
quantity_ordered = forms.IntegerField(required = False)
|
||||||
|
|
||||||
|
def __init__(self, *args, **kwargs):
|
||||||
|
super(OrderArticleForm, self).__init__(*args, **kwargs)
|
||||||
|
if 'initial' in kwargs:
|
||||||
|
self.name = kwargs['initial']['name']
|
||||||
|
self.stock = kwargs['initial']['stock']
|
||||||
|
self.category = kwargs['initial']['category']
|
||||||
|
self.category_name = kwargs['initial']['category__name']
|
||||||
|
self.box_capacity = kwargs['initial']['box_capacity']
|
||||||
|
self.v_s1 = kwargs['initial']['v_s1']
|
||||||
|
self.v_s2 = kwargs['initial']['v_s2']
|
||||||
|
self.v_s3 = kwargs['initial']['v_s3']
|
||||||
|
self.v_s4 = kwargs['initial']['v_s4']
|
||||||
|
self.v_s5 = kwargs['initial']['v_s5']
|
||||||
|
self.v_moy = kwargs['initial']['v_moy']
|
||||||
|
self.v_et = kwargs['initial']['v_et']
|
||||||
|
self.v_prev = kwargs['initial']['v_prev']
|
||||||
|
self.c_rec = kwargs['initial']['c_rec']
|
||||||
|
|
36
kfet/migrations/0038_auto_20160828_0402.py
Normal file
36
kfet/migrations/0038_auto_20160828_0402.py
Normal file
|
@ -0,0 +1,36 @@
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
from __future__ import unicode_literals
|
||||||
|
|
||||||
|
from django.db import models, migrations
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('kfet', '0037_auto_20160826_2333'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.AlterModelOptions(
|
||||||
|
name='inventory',
|
||||||
|
options={'ordering': ['-at']},
|
||||||
|
),
|
||||||
|
migrations.RemoveField(
|
||||||
|
model_name='supplierarticle',
|
||||||
|
name='box_capacity',
|
||||||
|
),
|
||||||
|
migrations.RemoveField(
|
||||||
|
model_name='supplierarticle',
|
||||||
|
name='box_type',
|
||||||
|
),
|
||||||
|
migrations.AddField(
|
||||||
|
model_name='article',
|
||||||
|
name='box_capacity',
|
||||||
|
field=models.PositiveSmallIntegerField(blank=True, null=True, default=None),
|
||||||
|
),
|
||||||
|
migrations.AddField(
|
||||||
|
model_name='article',
|
||||||
|
name='box_type',
|
||||||
|
field=models.CharField(max_length=7, blank=True, null=True, default=None, choices=[('caisse', 'Caisse'), ('carton', 'Carton'), ('palette', 'Palette'), ('fût', 'Fût')]),
|
||||||
|
),
|
||||||
|
]
|
24
kfet/migrations/0039_auto_20160828_0430.py
Normal file
24
kfet/migrations/0039_auto_20160828_0430.py
Normal file
|
@ -0,0 +1,24 @@
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
from __future__ import unicode_literals
|
||||||
|
|
||||||
|
from django.db import models, migrations
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('kfet', '0038_auto_20160828_0402'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name='order',
|
||||||
|
name='amount',
|
||||||
|
field=models.DecimalField(default=0, decimal_places=2, max_digits=6),
|
||||||
|
),
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name='orderarticle',
|
||||||
|
name='quantity_received',
|
||||||
|
field=models.IntegerField(default=0),
|
||||||
|
),
|
||||||
|
]
|
|
@ -325,6 +325,18 @@ class Article(models.Model):
|
||||||
category = models.ForeignKey(
|
category = models.ForeignKey(
|
||||||
ArticleCategory, on_delete = models.PROTECT,
|
ArticleCategory, on_delete = models.PROTECT,
|
||||||
related_name = "articles")
|
related_name = "articles")
|
||||||
|
BOX_TYPE_CHOICES = (
|
||||||
|
("caisse", "caisse"),
|
||||||
|
("carton", "carton"),
|
||||||
|
("palette", "palette"),
|
||||||
|
("fût", "fût"),
|
||||||
|
)
|
||||||
|
box_type = models.CharField(
|
||||||
|
choices = BOX_TYPE_CHOICES,
|
||||||
|
max_length = choices_length(BOX_TYPE_CHOICES),
|
||||||
|
blank = True, null = True, default = None)
|
||||||
|
box_capacity = models.PositiveSmallIntegerField(
|
||||||
|
blank = True, null = True, default = None)
|
||||||
|
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
return '%s - %s' % (self.category.name, self.name)
|
return '%s - %s' % (self.category.name, self.name)
|
||||||
|
@ -391,18 +403,6 @@ class SupplierArticle(models.Model):
|
||||||
Supplier, on_delete = models.PROTECT)
|
Supplier, on_delete = models.PROTECT)
|
||||||
article = models.ForeignKey(
|
article = models.ForeignKey(
|
||||||
Article, on_delete = models.PROTECT)
|
Article, on_delete = models.PROTECT)
|
||||||
BOX_TYPE_CHOICES = (
|
|
||||||
("caisse", "Caisse"),
|
|
||||||
("carton", "Carton"),
|
|
||||||
("palette", "Palette"),
|
|
||||||
("fût", "Fût"),
|
|
||||||
)
|
|
||||||
box_type = models.CharField(
|
|
||||||
choices = BOX_TYPE_CHOICES,
|
|
||||||
max_length = choices_length(BOX_TYPE_CHOICES),
|
|
||||||
blank = True, null = True, default = None)
|
|
||||||
box_capacity = models.PositiveSmallIntegerField(
|
|
||||||
blank = True, null = True, default = None)
|
|
||||||
price_HT = models.DecimalField(
|
price_HT = models.DecimalField(
|
||||||
max_digits = 7, decimal_places = 4,
|
max_digits = 7, decimal_places = 4,
|
||||||
blank = True, null = True, default = None)
|
blank = True, null = True, default = None)
|
||||||
|
@ -422,7 +422,11 @@ class Order(models.Model):
|
||||||
through = "OrderArticle",
|
through = "OrderArticle",
|
||||||
related_name = "orders")
|
related_name = "orders")
|
||||||
at = models.DateTimeField(auto_now_add = True)
|
at = models.DateTimeField(auto_now_add = True)
|
||||||
amount = models.DecimalField(max_digits = 6, decimal_places = 2)
|
amount = models.DecimalField(
|
||||||
|
max_digits = 6, decimal_places = 2, default = 0)
|
||||||
|
|
||||||
|
class Meta:
|
||||||
|
ordering = ['-at']
|
||||||
|
|
||||||
class OrderArticle(models.Model):
|
class OrderArticle(models.Model):
|
||||||
order = models.ForeignKey(
|
order = models.ForeignKey(
|
||||||
|
@ -430,7 +434,7 @@ class OrderArticle(models.Model):
|
||||||
article = models.ForeignKey(
|
article = models.ForeignKey(
|
||||||
Article, on_delete = models.PROTECT)
|
Article, on_delete = models.PROTECT)
|
||||||
quantity_ordered = models.IntegerField()
|
quantity_ordered = models.IntegerField()
|
||||||
quantity_received = models.IntegerField()
|
quantity_received = models.IntegerField(default = 0)
|
||||||
|
|
||||||
class TransferGroup(models.Model):
|
class TransferGroup(models.Model):
|
||||||
at = models.DateTimeField(auto_now_add = True)
|
at = models.DateTimeField(auto_now_add = True)
|
||||||
|
|
|
@ -17,19 +17,13 @@
|
||||||
<div class="col-sm-8 col-md-9 col-content-right">
|
<div class="col-sm-8 col-md-9 col-content-right">
|
||||||
{% include 'kfet/base_messages.html' %}
|
{% include 'kfet/base_messages.html' %}
|
||||||
<div class="content-right">
|
<div class="content-right">
|
||||||
<div class="content-right-block">
|
|
||||||
<h2>Liste des commandes</h2>
|
|
||||||
<div>
|
|
||||||
<table>
|
|
||||||
</table>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="content-right-block">
|
<div class="content-right-block">
|
||||||
<h2>Fournisseurs</h2>
|
<h2>Fournisseurs</h2>
|
||||||
<div>
|
<div>
|
||||||
<table class="table">
|
<table class="table">
|
||||||
<thead>
|
<thead>
|
||||||
<tr>
|
<tr>
|
||||||
|
<td></td>
|
||||||
<td></td>
|
<td></td>
|
||||||
<td>Nom</td>
|
<td>Nom</td>
|
||||||
<td>Mail</td>
|
<td>Mail</td>
|
||||||
|
@ -39,6 +33,11 @@
|
||||||
<tbody>
|
<tbody>
|
||||||
{% for supplier in suppliers %}
|
{% for supplier in suppliers %}
|
||||||
<tr>
|
<tr>
|
||||||
|
<td>
|
||||||
|
<a href="{% url 'kfet.order.new' supplier.pk %}" class="btn btn-primary">
|
||||||
|
Passer une commande
|
||||||
|
</a>
|
||||||
|
</td>
|
||||||
<td>
|
<td>
|
||||||
<a href="{% url 'kfet.order.supplier.update' supplier.pk %}">
|
<a href="{% url 'kfet.order.supplier.update' supplier.pk %}">
|
||||||
<span class="glyphicon glyphicon-cog"></span>
|
<span class="glyphicon glyphicon-cog"></span>
|
||||||
|
@ -55,6 +54,23 @@
|
||||||
</table>
|
</table>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="content-right-block">
|
||||||
|
<h2>Liste des commandes</h2>
|
||||||
|
<div>
|
||||||
|
<table>
|
||||||
|
{% for order in orders %}
|
||||||
|
<tr>
|
||||||
|
<td>
|
||||||
|
<a href="{% url 'kfet.order.read' order.pk %}">
|
||||||
|
{{ order.at }}
|
||||||
|
</a>
|
||||||
|
</td>
|
||||||
|
<td>{{ order.supplier }}</td>
|
||||||
|
</tr>
|
||||||
|
{% endfor %}
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
62
kfet/templates/kfet/order_create.html
Normal file
62
kfet/templates/kfet/order_create.html
Normal file
|
@ -0,0 +1,62 @@
|
||||||
|
{% extends 'kfet/base.html' %}
|
||||||
|
|
||||||
|
{% block title %}Nouvelle commande{% endblock %}
|
||||||
|
{% block content-header-title %}Nouvelle commande {{ supplier.name }}{% endblock %}
|
||||||
|
|
||||||
|
{% block content %}
|
||||||
|
|
||||||
|
<form action="" method="post">
|
||||||
|
{% csrf_token %}
|
||||||
|
<table>
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<td rowspan="2">Article</td>
|
||||||
|
<td colspan="5">Ventes</td>
|
||||||
|
<td rowspan="2">V. moy.</td>
|
||||||
|
<td rowspan="2">E.T.</td>
|
||||||
|
<td rowspan="2">Prév.</td>
|
||||||
|
<td rowspan="2">Stock</td>
|
||||||
|
<td rowspan="2">Rec.</td>
|
||||||
|
<td rowspan="2">Com.</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>S1</td>
|
||||||
|
<td>S2</td>
|
||||||
|
<td>S3</td>
|
||||||
|
<td>S4</td>
|
||||||
|
<td>S5</td>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
{% for form in formset %}
|
||||||
|
{% ifchanged form.category %}
|
||||||
|
<tr>
|
||||||
|
<td colspan="11">{{ form.category_name }}</td>
|
||||||
|
</tr>
|
||||||
|
{% endifchanged %}
|
||||||
|
<tr>
|
||||||
|
{{ form.article }}
|
||||||
|
<td>{{ form.name }}</td>
|
||||||
|
<td>{{ form.v_s1 }}</td>
|
||||||
|
<td>{{ form.v_s2 }}</td>
|
||||||
|
<td>{{ form.v_s3 }}</td>
|
||||||
|
<td>{{ form.v_s4 }}</td>
|
||||||
|
<td>{{ form.v_s5 }}</td>
|
||||||
|
<td>{{ form.v_moy }}</td>
|
||||||
|
<td>{{ form.v_et }}</td>
|
||||||
|
<td>{{ form.v_prev }}</td>
|
||||||
|
<td>{{ form.stock }}</td>
|
||||||
|
<td>{{ form.c_rec }}</td>
|
||||||
|
<td>{{ form.quantity_ordered }}</td>
|
||||||
|
</tr>
|
||||||
|
{% endfor %}
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
{% if not perms.kfet.add_order %}
|
||||||
|
<input type="password" name="KFETPASSWORD">
|
||||||
|
{% endif %}
|
||||||
|
{{ formset.management_form }}
|
||||||
|
<input type="submit" class="btn btn-primary btn-lg" value="Envoyer">
|
||||||
|
</form>
|
||||||
|
|
||||||
|
{% endblock %}
|
14
kfet/templates/kfet/order_read.html
Normal file
14
kfet/templates/kfet/order_read.html
Normal file
|
@ -0,0 +1,14 @@
|
||||||
|
{% extends 'kfet/base.html' %}
|
||||||
|
|
||||||
|
{% block title %}Commande #{{ order.pk }}{% endblock %}
|
||||||
|
{% block content-header-title %}Commande #{{ order.pk }}{% endblock %}
|
||||||
|
|
||||||
|
{% block content %}
|
||||||
|
|
||||||
|
<p>
|
||||||
|
Créée le {{ order.at }} pour {{ order.supplier.name }}
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<textarea>{{ mail }}</textarea>
|
||||||
|
|
||||||
|
{% endblock %}
|
|
@ -179,7 +179,12 @@ urlpatterns = [
|
||||||
url(r'^orders/$',
|
url(r'^orders/$',
|
||||||
permission_required('kfet.is_team')(views.OrderList.as_view()),
|
permission_required('kfet.is_team')(views.OrderList.as_view()),
|
||||||
name = 'kfet.order'),
|
name = 'kfet.order'),
|
||||||
|
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$',
|
url(r'^orders/suppliers/(?P<pk>\d+)/edit$',
|
||||||
permission_required('kfet.is_team')(views.SupplierUpdate.as_view()),
|
permission_required('kfet.is_team')(views.SupplierUpdate.as_view()),
|
||||||
name = 'kfet.order.supplier.update'),
|
name = 'kfet.order.supplier.update'),
|
||||||
|
url(r'^orders/suppliers/(?P<pk>\d+)/new-order$', views.order_create,
|
||||||
|
name = 'kfet.order.new'),
|
||||||
]
|
]
|
||||||
|
|
181
kfet/views.py
181
kfet/views.py
|
@ -12,19 +12,21 @@ 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, formset_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, Count
|
from django.db.models import F, Sum, Prefetch, Count, Func
|
||||||
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, Inventory,
|
CheckoutStatement, GenericTeamToken, Supplier, SupplierArticle, Inventory,
|
||||||
InventoryArticle, Order)
|
InventoryArticle, Order, OrderArticle)
|
||||||
from kfet.forms import *
|
from kfet.forms import *
|
||||||
from collections import defaultdict
|
from collections import defaultdict
|
||||||
from kfet import consumers
|
from kfet import consumers
|
||||||
import datetime
|
from datetime import timedelta
|
||||||
import django_cas_ng
|
import django_cas_ng
|
||||||
|
import heapq
|
||||||
|
import statistics
|
||||||
|
|
||||||
@login_required
|
@login_required
|
||||||
def home(request):
|
def home(request):
|
||||||
|
@ -1293,7 +1295,6 @@ def inventory_create(request):
|
||||||
.order_by('category__name', 'name')
|
.order_by('category__name', 'name')
|
||||||
)
|
)
|
||||||
initial = []
|
initial = []
|
||||||
data = []
|
|
||||||
for article in articles:
|
for article in articles:
|
||||||
initial.append({
|
initial.append({
|
||||||
'article' : article.pk,
|
'article' : article.pk,
|
||||||
|
@ -1324,6 +1325,7 @@ def inventory_create(request):
|
||||||
if form.cleaned_data['stock_new'] is not None:
|
if form.cleaned_data['stock_new'] is not None:
|
||||||
if not saved:
|
if not saved:
|
||||||
inventory.save()
|
inventory.save()
|
||||||
|
saved = True
|
||||||
|
|
||||||
article = articles.get(pk=form.cleaned_data['article'].pk)
|
article = articles.get(pk=form.cleaned_data['article'].pk)
|
||||||
stock_old = article.stock
|
stock_old = article.stock
|
||||||
|
@ -1356,13 +1358,182 @@ def inventory_create(request):
|
||||||
class OrderList(ListView):
|
class OrderList(ListView):
|
||||||
model = Order
|
model = Order
|
||||||
template_name = 'kfet/order.html'
|
template_name = 'kfet/order.html'
|
||||||
context_object_name = 'inventories'
|
context_object_name = 'orders'
|
||||||
|
|
||||||
def get_context_data(self, **kwargs):
|
def get_context_data(self, **kwargs):
|
||||||
context = super(OrderList, self).get_context_data(**kwargs)
|
context = super(OrderList, self).get_context_data(**kwargs)
|
||||||
context['suppliers'] = Supplier.objects.order_by('name')
|
context['suppliers'] = Supplier.objects.order_by('name')
|
||||||
return context
|
return context
|
||||||
|
|
||||||
|
@permission_required('kfet.is_team')
|
||||||
|
def order_create(request, pk):
|
||||||
|
supplier = Supplier.objects.get(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
|
||||||
|
.select_related('group')
|
||||||
|
.filter(article__in=articles, canceled_at=None)
|
||||||
|
.values('article'))
|
||||||
|
sales_s1 = (sales_q
|
||||||
|
.filter(
|
||||||
|
group__at__gte = today-timedelta(weeks=5),
|
||||||
|
group__at__lt = today-timedelta(weeks=4))
|
||||||
|
.annotate(nb=Sum('article_nb'))
|
||||||
|
)
|
||||||
|
sales_s1 = { d['article']:d['nb'] for d in sales_s1 }
|
||||||
|
sales_s2 = (sales_q
|
||||||
|
.filter(
|
||||||
|
group__at__gte = today-timedelta(weeks=4),
|
||||||
|
group__at__lt = today-timedelta(weeks=3))
|
||||||
|
.annotate(nb=Sum('article_nb'))
|
||||||
|
)
|
||||||
|
sales_s2 = { d['article']:d['nb'] for d in sales_s2 }
|
||||||
|
sales_s3 = (sales_q
|
||||||
|
.filter(
|
||||||
|
group__at__gte = today-timedelta(weeks=3),
|
||||||
|
group__at__lt = today-timedelta(weeks=2))
|
||||||
|
.annotate(nb=Sum('article_nb'))
|
||||||
|
)
|
||||||
|
sales_s3 = { d['article']:d['nb'] for d in sales_s3 }
|
||||||
|
sales_s4 = (sales_q
|
||||||
|
.filter(
|
||||||
|
group__at__gte = today-timedelta(weeks=2),
|
||||||
|
group__at__lt = today-timedelta(weeks=1))
|
||||||
|
.annotate(nb=Sum('article_nb'))
|
||||||
|
)
|
||||||
|
sales_s4 = { d['article']:d['nb'] for d in sales_s4 }
|
||||||
|
sales_s5 = (sales_q
|
||||||
|
.filter(group__at__gte = today-timedelta(weeks=1))
|
||||||
|
.annotate(nb=Sum('article_nb'))
|
||||||
|
)
|
||||||
|
sales_s5 = { d['article']:d['nb'] for d in sales_s5 }
|
||||||
|
|
||||||
|
for article in articles:
|
||||||
|
v_s1 = sales_s1.get(article.pk, 0)
|
||||||
|
v_s2 = sales_s2.get(article.pk, 0)
|
||||||
|
v_s3 = sales_s3.get(article.pk, 0)
|
||||||
|
v_s4 = sales_s4.get(article.pk, 0)
|
||||||
|
v_s5 = sales_s5.get(article.pk, 0)
|
||||||
|
v_all = [v_s1, v_s2, v_s3, v_s4, v_s5]
|
||||||
|
v_3max = heapq.nlargest(3, v_all)
|
||||||
|
v_moy = statistics.mean(v_3max)
|
||||||
|
v_et = statistics.pstdev(v_3max, v_moy)
|
||||||
|
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
|
||||||
|
if c_rec_temp >= 10:
|
||||||
|
c_rec = round(c_rec_temp)
|
||||||
|
elif c_rec_temp > 5:
|
||||||
|
c_rec = 10
|
||||||
|
elif c_rec_temp > 2:
|
||||||
|
c_rec = 5
|
||||||
|
else:
|
||||||
|
c_rec = round(c_rec_temp)
|
||||||
|
initial.append({
|
||||||
|
'article': article.pk,
|
||||||
|
'name': article.name,
|
||||||
|
'category': article.category_id,
|
||||||
|
'category__name': article.category.name,
|
||||||
|
'stock': article.stock,
|
||||||
|
'box_capacity': article.box_capacity,
|
||||||
|
'v_s1': v_s1,
|
||||||
|
'v_s2': v_s2,
|
||||||
|
'v_s3': v_s3,
|
||||||
|
'v_s4': v_s4,
|
||||||
|
'v_s5': v_s5,
|
||||||
|
'v_moy': round(v_moy),
|
||||||
|
'v_et': round(v_et),
|
||||||
|
'v_prev': round(v_prev),
|
||||||
|
'c_rec': article.box_capacity and c_rec or round(c_rec_tot),
|
||||||
|
})
|
||||||
|
|
||||||
|
cls_formset = formset_factory(
|
||||||
|
form = OrderArticleForm,
|
||||||
|
extra = 0)
|
||||||
|
|
||||||
|
if request.POST:
|
||||||
|
formset = cls_formset(request.POST, initial=initial)
|
||||||
|
|
||||||
|
if not request.user.has_perm('kfet.add_order'):
|
||||||
|
messages.error(request, 'Permission refusée')
|
||||||
|
elif formset.is_valid():
|
||||||
|
order = Order()
|
||||||
|
order.supplier = supplier
|
||||||
|
saved = False
|
||||||
|
for form in formset:
|
||||||
|
if form.cleaned_data['quantity_ordered'] is not None:
|
||||||
|
if not saved:
|
||||||
|
order.save()
|
||||||
|
saved = True
|
||||||
|
|
||||||
|
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
|
||||||
|
OrderArticle.objects.create(
|
||||||
|
order = order,
|
||||||
|
article = article,
|
||||||
|
quantity_ordered = q_ordered)
|
||||||
|
if saved:
|
||||||
|
messages.success(request, 'Commande créée')
|
||||||
|
return redirect('kfet.order.read', order.pk)
|
||||||
|
messages.warning(request, 'Rien commandé => Pas de commande')
|
||||||
|
else:
|
||||||
|
messages.error('Corrigez les erreurs')
|
||||||
|
else:
|
||||||
|
formset = cls_formset(initial=initial)
|
||||||
|
|
||||||
|
return render(request, 'kfet/order_create.html', {
|
||||||
|
'supplier': supplier,
|
||||||
|
'formset' : formset,
|
||||||
|
})
|
||||||
|
|
||||||
|
class OrderRead(DetailView):
|
||||||
|
model = Order
|
||||||
|
template_name = 'kfet/order_read.html'
|
||||||
|
context_object_name = 'order'
|
||||||
|
|
||||||
|
def get_context_data(self, **kwargs):
|
||||||
|
context = super(OrderRead, self).get_context_data(**kwargs)
|
||||||
|
orderarticles = (OrderArticle.objects
|
||||||
|
.select_related('article', 'article__category')
|
||||||
|
.filter(order=self.object)
|
||||||
|
.order_by('article__category__name', 'article__name')
|
||||||
|
)
|
||||||
|
mail = ("Bonjour,\n\nNous voudrions pour le ##DATE## à la K-Fêt de "
|
||||||
|
"l'ENS Ulm :")
|
||||||
|
category = 0
|
||||||
|
for orderarticle in orderarticles:
|
||||||
|
if category != orderarticle.article.category:
|
||||||
|
category = orderarticle.article.category
|
||||||
|
mail += '\n'
|
||||||
|
nb = orderarticle.quantity_ordered
|
||||||
|
box = ''
|
||||||
|
if orderarticle.article.box_capacity:
|
||||||
|
nb /= orderarticle.article.box_capacity
|
||||||
|
if nb >= 2:
|
||||||
|
box = ' %ss de' % orderarticle.article.box_type
|
||||||
|
else:
|
||||||
|
box = ' %s de' % orderarticle.article.box_type
|
||||||
|
name = orderarticle.article.name.capitalize()
|
||||||
|
mail += "\n- %s%s %s" % (round(nb), box, name)
|
||||||
|
|
||||||
|
mail += ("\n\nMerci d'appeler le numéro suivant lorsque les livreurs "
|
||||||
|
"sont là : ##TELEPHONE##\nCordialement,\n##PRENOM## ##NOM## "
|
||||||
|
", pour la K-Fêt de l'ENS Ulm")
|
||||||
|
|
||||||
|
context['mail'] = mail
|
||||||
|
return context
|
||||||
|
|
||||||
class SupplierUpdate(SuccessMessageMixin, UpdateView):
|
class SupplierUpdate(SuccessMessageMixin, UpdateView):
|
||||||
model = Supplier
|
model = Supplier
|
||||||
template_name = 'kfet/supplier_form.html'
|
template_name = 'kfet/supplier_form.html'
|
||||||
|
|
Loading…
Reference in a new issue