Merge branch 'qwann/k-fet/category_addcost' into 'master'
K-Fêt - Majorations - Seulement les catégories préalablement sélectionnées sont majorées le le cas échéant. - Pour modifier cette sélection, suivre le lien "Catégories" depuis la liste des articles. Fixes #149 See merge request !189
This commit is contained in:
commit
ebf948d042
10 changed files with 265 additions and 85 deletions
|
@ -233,6 +233,16 @@ class CheckoutStatementUpdateForm(forms.ModelForm):
|
||||||
model = CheckoutStatement
|
model = CheckoutStatement
|
||||||
exclude = ['by', 'at', 'checkout', 'amount_error', 'amount_taken']
|
exclude = ['by', 'at', 'checkout', 'amount_error', 'amount_taken']
|
||||||
|
|
||||||
|
|
||||||
|
# -----
|
||||||
|
# Category
|
||||||
|
# -----
|
||||||
|
|
||||||
|
class CategoryForm(forms.ModelForm):
|
||||||
|
class Meta:
|
||||||
|
model = ArticleCategory
|
||||||
|
fields = ['name', 'has_addcost']
|
||||||
|
|
||||||
# -----
|
# -----
|
||||||
# Article forms
|
# Article forms
|
||||||
# -----
|
# -----
|
||||||
|
|
24
kfet/migrations/0052_category_addcost.py
Normal file
24
kfet/migrations/0052_category_addcost.py
Normal file
|
@ -0,0 +1,24 @@
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
from __future__ import unicode_literals
|
||||||
|
|
||||||
|
from django.db import migrations, models
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('kfet', '0051_verbose_names'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.AddField(
|
||||||
|
model_name='articlecategory',
|
||||||
|
name='has_addcost',
|
||||||
|
field=models.BooleanField(default=True, help_text="Si oui et qu'une majoration est active, celle-ci sera appliquée aux articles de cette catégorie.", verbose_name='majorée'),
|
||||||
|
),
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name='articlecategory',
|
||||||
|
name='name',
|
||||||
|
field=models.CharField(max_length=45, verbose_name='nom'),
|
||||||
|
),
|
||||||
|
]
|
|
@ -338,13 +338,20 @@ class CheckoutStatement(models.Model):
|
||||||
balance=F('balance') - last_statement.balance_new + self.balance_new)
|
balance=F('balance') - last_statement.balance_new + self.balance_new)
|
||||||
super(CheckoutStatement, self).save(*args, **kwargs)
|
super(CheckoutStatement, self).save(*args, **kwargs)
|
||||||
|
|
||||||
|
|
||||||
@python_2_unicode_compatible
|
@python_2_unicode_compatible
|
||||||
class ArticleCategory(models.Model):
|
class ArticleCategory(models.Model):
|
||||||
name = models.CharField(max_length = 45)
|
name = models.CharField("nom", max_length=45)
|
||||||
|
has_addcost = models.BooleanField("majorée", default=True,
|
||||||
|
help_text="Si oui et qu'une majoration "
|
||||||
|
"est active, celle-ci sera "
|
||||||
|
"appliquée aux articles de "
|
||||||
|
"cette catégorie.")
|
||||||
|
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
return self.name
|
return self.name
|
||||||
|
|
||||||
|
|
||||||
@python_2_unicode_compatible
|
@python_2_unicode_compatible
|
||||||
class Article(models.Model):
|
class Article(models.Model):
|
||||||
name = models.CharField("nom", max_length = 45)
|
name = models.CharField("nom", max_length = 45)
|
||||||
|
|
|
@ -16,6 +16,9 @@
|
||||||
<a class="btn btn-primary btn-lg" href="{% url 'kfet.article.create' %}">
|
<a class="btn btn-primary btn-lg" href="{% url 'kfet.article.create' %}">
|
||||||
Nouvel article
|
Nouvel article
|
||||||
</a>
|
</a>
|
||||||
|
<a class="btn btn-primary btn-lg" href="{% url 'kfet.category' %}">
|
||||||
|
Catégories
|
||||||
|
</a>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -12,7 +12,7 @@
|
||||||
<div class="row form-only">
|
<div class="row form-only">
|
||||||
<div class="col-sm-12 col-md-8 col-md-offset-2">
|
<div class="col-sm-12 col-md-8 col-md-offset-2">
|
||||||
<div class="content-form">
|
<div class="content-form">
|
||||||
<form submit="" method="post" class="form-horizontal">
|
<form action="" method="post" class="form-horizontal">
|
||||||
{% csrf_token %}
|
{% csrf_token %}
|
||||||
{% include 'kfet/form_snippet.html' with form=form %}
|
{% include 'kfet/form_snippet.html' with form=form %}
|
||||||
{% if not perms.kfet.change_article %}
|
{% if not perms.kfet.change_article %}
|
||||||
|
|
53
kfet/templates/kfet/category.html
Normal file
53
kfet/templates/kfet/category.html
Normal file
|
@ -0,0 +1,53 @@
|
||||||
|
{% extends 'kfet/base.html' %}
|
||||||
|
|
||||||
|
{% block title %}Categories d'articles{% endblock %}
|
||||||
|
{% block content-header-title %}Categories d'articles{% 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 class="line line-big">{{ categories|length }}</div>
|
||||||
|
<div class="line line-bigsub">catégorie{{ categories|length|pluralize }}</div>
|
||||||
|
</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 catégories</h2>
|
||||||
|
<div class="table-responsive">
|
||||||
|
<table class="table table-condensed">
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<td></td>
|
||||||
|
<td>Nom</td>
|
||||||
|
<td class="text-right">Nombre d'articles</td>
|
||||||
|
<td class="text-right">Peut être majorée</td>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
{% for category in categories %}
|
||||||
|
<tr>
|
||||||
|
<td class="text-center">
|
||||||
|
<a href="{% url 'kfet.category.update' category.pk %}">
|
||||||
|
<span class="glyphicon glyphicon-cog"></span>
|
||||||
|
</a>
|
||||||
|
</td>
|
||||||
|
<td>{{ category.name }}</td>
|
||||||
|
<td class="text-right">{{ category.articles.all|length }}</td>
|
||||||
|
<td class="text-right">{{ category.has_addcost | yesno:"Oui,Non"}}</td>
|
||||||
|
</tr>
|
||||||
|
{% endfor %}
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{% endblock %}
|
25
kfet/templates/kfet/category_update.html
Normal file
25
kfet/templates/kfet/category_update.html
Normal file
|
@ -0,0 +1,25 @@
|
||||||
|
{% extends 'kfet/base.html' %}
|
||||||
|
|
||||||
|
{% block title %}Édition de la catégorie {{ category.name }}{% endblock %}
|
||||||
|
{% block content-header-title %}Catégorie {{ category.name }} - Édition{% endblock %}
|
||||||
|
|
||||||
|
{% block content %}
|
||||||
|
|
||||||
|
{% include "kfet/base_messages.html" %}
|
||||||
|
|
||||||
|
<div class="row form-only">
|
||||||
|
<div class="col-sm-12 col-md-8 col-md-offset-2">
|
||||||
|
<div class="content-form">
|
||||||
|
<form action="" method="post" class="form-horizontal">
|
||||||
|
{% csrf_token %}
|
||||||
|
{% include 'kfet/form_snippet.html' with form=form %}
|
||||||
|
{% if not perms.kfet.edit_articlecategory %}
|
||||||
|
{% include 'kfet/form_authentication_snippet.html' %}
|
||||||
|
{% endif %}
|
||||||
|
{% include 'kfet/form_submit_snippet.html' with value="Enregistrer"%}
|
||||||
|
<form>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{% endblock %}
|
|
@ -647,7 +647,7 @@ $(document).ready(function() {
|
||||||
});
|
});
|
||||||
$after.after(article_html);
|
$after.after(article_html);
|
||||||
// Pour l'autocomplétion
|
// Pour l'autocomplétion
|
||||||
articlesList.push([article['name'],article['id'],article['category_id'],article['price'], article['stock']]);
|
articlesList.push([article['name'],article['id'],article['category_id'],article['price'], article['stock'],article['category__has_addcost']]);
|
||||||
}
|
}
|
||||||
|
|
||||||
function getArticles() {
|
function getArticles() {
|
||||||
|
@ -831,8 +831,11 @@ $(document).ready(function() {
|
||||||
while (i<articlesList.length && id != articlesList[i][1]) i++;
|
while (i<articlesList.length && id != articlesList[i][1]) i++;
|
||||||
article_data = articlesList[i];
|
article_data = articlesList[i];
|
||||||
var amount_euro = - article_data[3] * nb ;
|
var amount_euro = - article_data[3] * nb ;
|
||||||
if (settings['addcost_for'] && settings['addcost_amount'] && account_data['trigramme'] != settings['addcost_for'])
|
if (settings['addcost_for']
|
||||||
amount_euro -= settings['addcost_amount'] * nb;
|
&& settings['addcost_amount']
|
||||||
|
&& account_data['trigramme'] != settings['addcost_for']
|
||||||
|
&& article_data[5])
|
||||||
|
amount_euro -= settings['addcost_amount'] * nb;
|
||||||
var reduc_divisor = 1;
|
var reduc_divisor = 1;
|
||||||
if (account_data['is_cof'])
|
if (account_data['is_cof'])
|
||||||
reduc_divisor = 1 + settings['subvention_cof'] / 100;
|
reduc_divisor = 1 + settings['subvention_cof'] / 100;
|
||||||
|
|
14
kfet/urls.py
14
kfet/urls.py
|
@ -8,7 +8,7 @@ from kfet.decorators import teamkfet_required
|
||||||
|
|
||||||
urlpatterns = [
|
urlpatterns = [
|
||||||
url(r'^$', views.Home.as_view(),
|
url(r'^$', views.Home.as_view(),
|
||||||
name = 'kfet.home'),
|
name='kfet.home'),
|
||||||
url(r'^login/genericteam$', views.login_genericteam,
|
url(r'^login/genericteam$', views.login_genericteam,
|
||||||
name='kfet.login.genericteam'),
|
name='kfet.login.genericteam'),
|
||||||
url(r'^history$', views.history,
|
url(r'^history$', views.history,
|
||||||
|
@ -69,10 +69,10 @@ urlpatterns = [
|
||||||
name='kfet.account.negative'),
|
name='kfet.account.negative'),
|
||||||
|
|
||||||
# Account - Statistics
|
# Account - Statistics
|
||||||
url('^accounts/(?P<trigramme>.{3})/stat/operations/list$',
|
url(r'^accounts/(?P<trigramme>.{3})/stat/operations/list$',
|
||||||
views.AccountStatOperationList.as_view(),
|
views.AccountStatOperationList.as_view(),
|
||||||
name='kfet.account.stat.operation.list'),
|
name='kfet.account.stat.operation.list'),
|
||||||
url('^accounts/(?P<trigramme>.{3})/stat/operations$',
|
url(r'^accounts/(?P<trigramme>.{3})/stat/operations$',
|
||||||
views.AccountStatOperation.as_view(),
|
views.AccountStatOperation.as_view(),
|
||||||
name='kfet.account.stat.operation'),
|
name='kfet.account.stat.operation'),
|
||||||
|
|
||||||
|
@ -125,6 +125,14 @@ urlpatterns = [
|
||||||
# Article urls
|
# Article urls
|
||||||
# -----
|
# -----
|
||||||
|
|
||||||
|
# Category - General
|
||||||
|
url('^categories/$',
|
||||||
|
teamkfet_required(views.CategoryList.as_view()),
|
||||||
|
name='kfet.category'),
|
||||||
|
# Category - Update
|
||||||
|
url('^categories/(?P<pk>\d+)/edit$',
|
||||||
|
teamkfet_required(views.CategoryUpdate.as_view()),
|
||||||
|
name='kfet.category.update'),
|
||||||
# Article - General
|
# Article - General
|
||||||
url('^articles/$',
|
url('^articles/$',
|
||||||
teamkfet_required(views.ArticleList.as_view()),
|
teamkfet_required(views.ArticleList.as_view()),
|
||||||
|
|
201
kfet/views.py
201
kfet/views.py
|
@ -29,7 +29,7 @@ from kfet.models import (
|
||||||
Account, Checkout, Article, Settings, AccountNegative,
|
Account, Checkout, Article, Settings, AccountNegative,
|
||||||
CheckoutStatement, GenericTeamToken, Supplier, SupplierArticle, Inventory,
|
CheckoutStatement, GenericTeamToken, Supplier, SupplierArticle, Inventory,
|
||||||
InventoryArticle, Order, OrderArticle, Operation, OperationGroup,
|
InventoryArticle, Order, OrderArticle, Operation, OperationGroup,
|
||||||
TransferGroup, Transfer)
|
TransferGroup, Transfer, ArticleCategory)
|
||||||
from kfet.forms import (
|
from kfet.forms import (
|
||||||
AccountTriForm, AccountBalanceForm, AccountNoTriForm, UserForm, CofForm,
|
AccountTriForm, AccountBalanceForm, AccountNoTriForm, UserForm, CofForm,
|
||||||
UserRestrictTeamForm, UserGroupForm, AccountForm, CofRestrictForm,
|
UserRestrictTeamForm, UserGroupForm, AccountForm, CofRestrictForm,
|
||||||
|
@ -39,7 +39,7 @@ from kfet.forms import (
|
||||||
KPsulOperationGroupForm, KPsulAccountForm, KPsulCheckoutForm,
|
KPsulOperationGroupForm, KPsulAccountForm, KPsulCheckoutForm,
|
||||||
KPsulOperationFormSet, AddcostForm, FilterHistoryForm, SettingsForm,
|
KPsulOperationFormSet, AddcostForm, FilterHistoryForm, SettingsForm,
|
||||||
TransferFormSet, InventoryArticleForm, OrderArticleForm,
|
TransferFormSet, InventoryArticleForm, OrderArticleForm,
|
||||||
OrderArticleToInventoryForm
|
OrderArticleToInventoryForm, CategoryForm
|
||||||
)
|
)
|
||||||
from collections import defaultdict
|
from collections import defaultdict
|
||||||
from kfet import consumers
|
from kfet import consumers
|
||||||
|
@ -52,7 +52,7 @@ from kfet.statistic import ScaleMixin, last_stats_manifest, tot_ventes
|
||||||
|
|
||||||
|
|
||||||
class Home(TemplateView):
|
class Home(TemplateView):
|
||||||
template_name = "kfet/home.html"
|
template_name = "kfet/home.html"
|
||||||
|
|
||||||
def get_context_data(self, **kwargs):
|
def get_context_data(self, **kwargs):
|
||||||
context = super(TemplateView, self).get_context_data(**kwargs)
|
context = super(TemplateView, self).get_context_data(**kwargs)
|
||||||
|
@ -723,28 +723,60 @@ class CheckoutStatementUpdate(SuccessMessageMixin, UpdateView):
|
||||||
form.instance.amount_taken = getAmountTaken(form.instance)
|
form.instance.amount_taken = getAmountTaken(form.instance)
|
||||||
return super(CheckoutStatementUpdate, self).form_valid(form)
|
return super(CheckoutStatementUpdate, self).form_valid(form)
|
||||||
|
|
||||||
|
# -----
|
||||||
|
# Category views
|
||||||
|
# -----
|
||||||
|
|
||||||
|
|
||||||
|
# Category - General
|
||||||
|
class CategoryList(ListView):
|
||||||
|
queryset = (ArticleCategory.objects
|
||||||
|
.prefetch_related('articles')
|
||||||
|
.order_by('name'))
|
||||||
|
template_name = 'kfet/category.html'
|
||||||
|
context_object_name = 'categories'
|
||||||
|
|
||||||
|
|
||||||
|
# Category - Update
|
||||||
|
class CategoryUpdate(SuccessMessageMixin, UpdateView):
|
||||||
|
model = ArticleCategory
|
||||||
|
template_name = 'kfet/category_update.html'
|
||||||
|
form_class = CategoryForm
|
||||||
|
success_url = reverse_lazy('kfet.category')
|
||||||
|
success_message = "Informations mises à jour pour la catégorie : %(name)s"
|
||||||
|
|
||||||
|
# Surcharge de la validation
|
||||||
|
def form_valid(self, form):
|
||||||
|
# Checking permission
|
||||||
|
if not self.request.user.has_perm('kfet.change_articlecategory'):
|
||||||
|
form.add_error(None, 'Permission refusée')
|
||||||
|
return self.form_invalid(form)
|
||||||
|
|
||||||
|
# Updating
|
||||||
|
return super(CategoryUpdate, self).form_valid(form)
|
||||||
|
|
||||||
# -----
|
# -----
|
||||||
# Article views
|
# Article views
|
||||||
# -----
|
# -----
|
||||||
|
|
||||||
# Article - General
|
|
||||||
|
|
||||||
|
# Article - General
|
||||||
class ArticleList(ListView):
|
class ArticleList(ListView):
|
||||||
queryset = (Article.objects
|
queryset = (Article.objects
|
||||||
.select_related('category')
|
.select_related('category')
|
||||||
.prefetch_related(Prefetch('inventories',
|
.prefetch_related(Prefetch('inventories',
|
||||||
queryset = Inventory.objects.order_by('-at'),
|
queryset=Inventory.objects.order_by('-at'),
|
||||||
to_attr = 'inventory'))
|
to_attr='inventory'))
|
||||||
.order_by('category', '-is_sold', 'name'))
|
.order_by('category', '-is_sold', 'name'))
|
||||||
template_name = 'kfet/article.html'
|
template_name = 'kfet/article.html'
|
||||||
context_object_name = 'articles'
|
context_object_name = 'articles'
|
||||||
|
|
||||||
# Article - Create
|
|
||||||
|
|
||||||
|
# Article - Create
|
||||||
class ArticleCreate(SuccessMessageMixin, CreateView):
|
class ArticleCreate(SuccessMessageMixin, CreateView):
|
||||||
model = Article
|
model = Article
|
||||||
template_name = 'kfet/article_create.html'
|
template_name = 'kfet/article_create.html'
|
||||||
form_class = ArticleForm
|
form_class = ArticleForm
|
||||||
success_message = 'Nouvel item : %(category)s - %(name)s'
|
success_message = 'Nouvel item : %(category)s - %(name)s'
|
||||||
|
|
||||||
# Surcharge de la validation
|
# Surcharge de la validation
|
||||||
|
@ -759,7 +791,7 @@ class ArticleCreate(SuccessMessageMixin, CreateView):
|
||||||
# Save des suppliers déjà existant
|
# Save des suppliers déjà existant
|
||||||
for supplier in form.cleaned_data['suppliers']:
|
for supplier in form.cleaned_data['suppliers']:
|
||||||
SupplierArticle.objects.create(
|
SupplierArticle.objects.create(
|
||||||
article = article, supplier = supplier)
|
article=article, supplier=supplier)
|
||||||
|
|
||||||
# Nouveau supplier
|
# Nouveau supplier
|
||||||
supplier_new = form.cleaned_data['supplier_new'].strip()
|
supplier_new = form.cleaned_data['supplier_new'].strip()
|
||||||
|
@ -768,49 +800,49 @@ class ArticleCreate(SuccessMessageMixin, CreateView):
|
||||||
name=supplier_new)
|
name=supplier_new)
|
||||||
if created:
|
if created:
|
||||||
SupplierArticle.objects.create(
|
SupplierArticle.objects.create(
|
||||||
article = article, supplier = supplier)
|
article=article, supplier=supplier)
|
||||||
|
|
||||||
# Inventaire avec stock initial
|
# Inventaire avec stock initial
|
||||||
inventory = Inventory()
|
inventory = Inventory()
|
||||||
inventory.by = self.request.user.profile.account_kfet
|
inventory.by = self.request.user.profile.account_kfet
|
||||||
inventory.save()
|
inventory.save()
|
||||||
InventoryArticle.objects.create(
|
InventoryArticle.objects.create(
|
||||||
inventory = inventory,
|
inventory=inventory,
|
||||||
article = article,
|
article=article,
|
||||||
stock_old = article.stock,
|
stock_old=article.stock,
|
||||||
stock_new = article.stock,
|
stock_new=article.stock,
|
||||||
)
|
)
|
||||||
|
|
||||||
# Creating
|
# Creating
|
||||||
return super(ArticleCreate, self).form_valid(form)
|
return super(ArticleCreate, self).form_valid(form)
|
||||||
|
|
||||||
# Article - Read
|
|
||||||
|
|
||||||
|
# Article - Read
|
||||||
class ArticleRead(DetailView):
|
class ArticleRead(DetailView):
|
||||||
model = Article
|
model = Article
|
||||||
template_name = 'kfet/article_read.html'
|
template_name = 'kfet/article_read.html'
|
||||||
context_object_name = 'article'
|
context_object_name = 'article'
|
||||||
|
|
||||||
def get_context_data(self, **kwargs):
|
def get_context_data(self, **kwargs):
|
||||||
context = super(ArticleRead, self).get_context_data(**kwargs)
|
context = super(ArticleRead, self).get_context_data(**kwargs)
|
||||||
inventoryarts = (InventoryArticle.objects
|
inventoryarts = (InventoryArticle.objects
|
||||||
.filter(article = self.object)
|
.filter(article=self.object)
|
||||||
.select_related('inventory')
|
.select_related('inventory')
|
||||||
.order_by('-inventory__at'))
|
.order_by('-inventory__at'))
|
||||||
context['inventoryarts'] = inventoryarts
|
context['inventoryarts'] = inventoryarts
|
||||||
supplierarts = (SupplierArticle.objects
|
supplierarts = (SupplierArticle.objects
|
||||||
.filter(article = self.object)
|
.filter(article=self.object)
|
||||||
.select_related('supplier')
|
.select_related('supplier')
|
||||||
.order_by('-at'))
|
.order_by('-at'))
|
||||||
context['supplierarts'] = supplierarts
|
context['supplierarts'] = supplierarts
|
||||||
return context
|
return context
|
||||||
|
|
||||||
# Article - Update
|
|
||||||
|
|
||||||
|
# Article - Update
|
||||||
class ArticleUpdate(SuccessMessageMixin, UpdateView):
|
class ArticleUpdate(SuccessMessageMixin, UpdateView):
|
||||||
model = Article
|
model = Article
|
||||||
template_name = 'kfet/article_update.html'
|
template_name = 'kfet/article_update.html'
|
||||||
form_class = ArticleRestrictForm
|
form_class = ArticleRestrictForm
|
||||||
success_message = "Informations mises à jour pour l'article : %(name)s"
|
success_message = "Informations mises à jour pour l'article : %(name)s"
|
||||||
|
|
||||||
# Surcharge de la validation
|
# Surcharge de la validation
|
||||||
|
@ -826,13 +858,13 @@ class ArticleUpdate(SuccessMessageMixin, UpdateView):
|
||||||
for supplier in form.cleaned_data['suppliers']:
|
for supplier in form.cleaned_data['suppliers']:
|
||||||
if supplier not in article.suppliers.all():
|
if supplier not in article.suppliers.all():
|
||||||
SupplierArticle.objects.create(
|
SupplierArticle.objects.create(
|
||||||
article = article, supplier = supplier)
|
article=article, supplier=supplier)
|
||||||
|
|
||||||
# On vire les suppliers désélectionnés
|
# On vire les suppliers désélectionnés
|
||||||
for supplier in article.suppliers.all():
|
for supplier in article.suppliers.all():
|
||||||
if supplier not in form.cleaned_data['suppliers']:
|
if supplier not in form.cleaned_data['suppliers']:
|
||||||
SupplierArticle.objects.filter(
|
SupplierArticle.objects.filter(
|
||||||
article = article, supplier = supplier).delete()
|
article=article, supplier=supplier).delete()
|
||||||
|
|
||||||
# Nouveau supplier
|
# Nouveau supplier
|
||||||
supplier_new = form.cleaned_data['supplier_new'].strip()
|
supplier_new = form.cleaned_data['supplier_new'].strip()
|
||||||
|
@ -841,7 +873,7 @@ class ArticleUpdate(SuccessMessageMixin, UpdateView):
|
||||||
name=supplier_new)
|
name=supplier_new)
|
||||||
if created:
|
if created:
|
||||||
SupplierArticle.objects.create(
|
SupplierArticle.objects.create(
|
||||||
article = article, supplier = supplier)
|
article=article, supplier=supplier)
|
||||||
|
|
||||||
# Updating
|
# Updating
|
||||||
return super(ArticleUpdate, self).form_valid(form)
|
return super(ArticleUpdate, self).form_valid(form)
|
||||||
|
@ -924,13 +956,14 @@ def kpsul_update_addcost(request):
|
||||||
addcost_form = AddcostForm(request.POST)
|
addcost_form = AddcostForm(request.POST)
|
||||||
|
|
||||||
if not addcost_form.is_valid():
|
if not addcost_form.is_valid():
|
||||||
data = { 'errors': { 'addcost': list(addcost_form.errors) } }
|
data = {'errors': {'addcost': list(addcost_form.errors)}}
|
||||||
return JsonResponse(data, status=400)
|
return JsonResponse(data, status=400)
|
||||||
required_perms = ['kfet.manage_addcosts']
|
required_perms = ['kfet.manage_addcosts']
|
||||||
if not request.user.has_perms(required_perms):
|
if not request.user.has_perms(required_perms):
|
||||||
data = {
|
data = {
|
||||||
'errors': {
|
'errors': {
|
||||||
'missing_perms': get_missing_perms(required_perms, request.user)
|
'missing_perms': get_missing_perms(required_perms,
|
||||||
|
request.user)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return JsonResponse(data, status=403)
|
return JsonResponse(data, status=403)
|
||||||
|
@ -938,7 +971,8 @@ def kpsul_update_addcost(request):
|
||||||
trigramme = addcost_form.cleaned_data['trigramme']
|
trigramme = addcost_form.cleaned_data['trigramme']
|
||||||
account = trigramme and Account.objects.get(trigramme=trigramme) or None
|
account = trigramme and Account.objects.get(trigramme=trigramme) or None
|
||||||
Settings.objects.filter(name='ADDCOST_FOR').update(value_account=account)
|
Settings.objects.filter(name='ADDCOST_FOR').update(value_account=account)
|
||||||
Settings.objects.filter(name='ADDCOST_AMOUNT').update(value_decimal=addcost_form.cleaned_data['amount'])
|
(Settings.objects.filter(name='ADDCOST_AMOUNT')
|
||||||
|
.update(value_decimal=addcost_form.cleaned_data['amount']))
|
||||||
cache.delete('ADDCOST_FOR')
|
cache.delete('ADDCOST_FOR')
|
||||||
cache.delete('ADDCOST_AMOUNT')
|
cache.delete('ADDCOST_AMOUNT')
|
||||||
data = {
|
data = {
|
||||||
|
@ -950,20 +984,24 @@ def kpsul_update_addcost(request):
|
||||||
consumers.KPsul.group_send('kfet.kpsul', data)
|
consumers.KPsul.group_send('kfet.kpsul', data)
|
||||||
return JsonResponse(data)
|
return JsonResponse(data)
|
||||||
|
|
||||||
|
|
||||||
def get_missing_perms(required_perms, user):
|
def get_missing_perms(required_perms, user):
|
||||||
missing_perms_codenames = [ (perm.split('.'))[1]
|
missing_perms_codenames = [(perm.split('.'))[1]
|
||||||
for perm in required_perms if not user.has_perm(perm)]
|
for perm in required_perms
|
||||||
|
if not user.has_perm(perm)]
|
||||||
missing_perms = list(
|
missing_perms = list(
|
||||||
Permission.objects
|
Permission.objects
|
||||||
.filter(codename__in=missing_perms_codenames)
|
.filter(codename__in=missing_perms_codenames)
|
||||||
.values_list('name', flat=True))
|
.values_list('name', flat=True)
|
||||||
|
)
|
||||||
return missing_perms
|
return missing_perms
|
||||||
|
|
||||||
|
|
||||||
@teamkfet_required
|
@teamkfet_required
|
||||||
def kpsul_perform_operations(request):
|
def kpsul_perform_operations(request):
|
||||||
# Initializing response data
|
# Initializing response data
|
||||||
data = { 'operationgroup': 0, 'operations': [],
|
data = {'operationgroup': 0, 'operations': [],
|
||||||
'warnings': {}, 'errors': {} }
|
'warnings': {}, 'errors': {}}
|
||||||
|
|
||||||
# Checking operationgroup
|
# Checking operationgroup
|
||||||
operationgroup_form = KPsulOperationGroupForm(request.POST)
|
operationgroup_form = KPsulOperationGroupForm(request.POST)
|
||||||
|
@ -971,7 +1009,7 @@ def kpsul_perform_operations(request):
|
||||||
data['errors']['operation_group'] = list(operationgroup_form.errors)
|
data['errors']['operation_group'] = list(operationgroup_form.errors)
|
||||||
|
|
||||||
# Checking operation_formset
|
# Checking operation_formset
|
||||||
operation_formset = KPsulOperationFormSet(request.POST)
|
operation_formset = KPsulOperationFormSet(request.POST)
|
||||||
if not operation_formset.is_valid():
|
if not operation_formset.is_valid():
|
||||||
data['errors']['operations'] = list(operation_formset.errors)
|
data['errors']['operations'] = list(operation_formset.errors)
|
||||||
|
|
||||||
|
@ -980,39 +1018,41 @@ def kpsul_perform_operations(request):
|
||||||
return JsonResponse(data, status=400)
|
return JsonResponse(data, status=400)
|
||||||
|
|
||||||
# Pre-saving (no commit)
|
# Pre-saving (no commit)
|
||||||
operationgroup = operationgroup_form.save(commit = False)
|
operationgroup = operationgroup_form.save(commit=False)
|
||||||
operations = operation_formset.save(commit = False)
|
operations = operation_formset.save(commit=False)
|
||||||
|
|
||||||
# Retrieving COF grant
|
# Retrieving COF grant
|
||||||
cof_grant = Settings.SUBVENTION_COF()
|
cof_grant = Settings.SUBVENTION_COF()
|
||||||
# Retrieving addcosts data
|
# Retrieving addcosts data
|
||||||
addcost_amount = Settings.ADDCOST_AMOUNT()
|
addcost_amount = Settings.ADDCOST_AMOUNT()
|
||||||
addcost_for = Settings.ADDCOST_FOR()
|
addcost_for = Settings.ADDCOST_FOR()
|
||||||
|
|
||||||
# Initializing vars
|
# Initializing vars
|
||||||
required_perms = set() # Required perms to perform all operations
|
required_perms = set() # Required perms to perform all operations
|
||||||
cof_grant_divisor = 1 + cof_grant / 100
|
cof_grant_divisor = 1 + cof_grant / 100
|
||||||
to_addcost_for_balance = 0 # For balance of addcost_for
|
to_addcost_for_balance = 0 # For balance of addcost_for
|
||||||
to_checkout_balance = 0 # For balance of selected checkout
|
to_checkout_balance = 0 # For balance of selected checkout
|
||||||
to_articles_stocks = defaultdict(lambda:0) # For stocks articles
|
to_articles_stocks = defaultdict(lambda: 0) # For stocks articles
|
||||||
is_addcost = (addcost_for and addcost_amount
|
is_addcost = all((addcost_for, addcost_amount,
|
||||||
and addcost_for != operationgroup.on_acc)
|
addcost_for != operationgroup.on_acc))
|
||||||
need_comment = operationgroup.on_acc.need_comment
|
need_comment = operationgroup.on_acc.need_comment
|
||||||
|
|
||||||
# Filling data of each operations + operationgroup + calculating other stuffs
|
# Filling data of each operations
|
||||||
|
# + operationgroup + calculating other stuffs
|
||||||
for operation in operations:
|
for operation in operations:
|
||||||
if operation.type == Operation.PURCHASE:
|
if operation.type == Operation.PURCHASE:
|
||||||
operation.amount = - operation.article.price * operation.article_nb
|
operation.amount = - operation.article.price * operation.article_nb
|
||||||
if is_addcost:
|
if is_addcost & operation.article.category.has_addcost:
|
||||||
operation.addcost_for = addcost_for
|
operation.addcost_for = addcost_for
|
||||||
operation.addcost_amount = addcost_amount * operation.article_nb
|
operation.addcost_amount = addcost_amount \
|
||||||
operation.amount -= operation.addcost_amount
|
* operation.article_nb
|
||||||
to_addcost_for_balance += operation.addcost_amount
|
operation.amount -= operation.addcost_amount
|
||||||
|
to_addcost_for_balance += operation.addcost_amount
|
||||||
if operationgroup.on_acc.is_cash:
|
if operationgroup.on_acc.is_cash:
|
||||||
to_checkout_balance += -operation.amount
|
to_checkout_balance += -operation.amount
|
||||||
if operationgroup.on_acc.is_cof:
|
if operationgroup.on_acc.is_cof:
|
||||||
if is_addcost:
|
if is_addcost and operation.article.category.has_addcost:
|
||||||
operation.addcost_amount = operation.addcost_amount / cof_grant_divisor
|
operation.addcost_amount /= cof_grant_divisor
|
||||||
operation.amount = operation.amount / cof_grant_divisor
|
operation.amount = operation.amount / cof_grant_divisor
|
||||||
to_articles_stocks[operation.article] -= operation.article_nb
|
to_articles_stocks[operation.article] -= operation.article_nb
|
||||||
else:
|
else:
|
||||||
|
@ -1029,8 +1069,10 @@ def kpsul_perform_operations(request):
|
||||||
if operationgroup.on_acc.is_cof:
|
if operationgroup.on_acc.is_cof:
|
||||||
to_addcost_for_balance = to_addcost_for_balance / cof_grant_divisor
|
to_addcost_for_balance = to_addcost_for_balance / cof_grant_divisor
|
||||||
|
|
||||||
(perms, stop) = operationgroup.on_acc.perms_to_perform_operation(
|
(perms, stop) = (operationgroup.on_acc
|
||||||
amount = operationgroup.amount)
|
.perms_to_perform_operation(
|
||||||
|
amount=operationgroup.amount)
|
||||||
|
)
|
||||||
required_perms |= perms
|
required_perms |= perms
|
||||||
|
|
||||||
if need_comment:
|
if need_comment:
|
||||||
|
@ -1061,7 +1103,7 @@ def kpsul_perform_operations(request):
|
||||||
# saving account's balance and adding to Negative if not in
|
# saving account's balance and adding to Negative if not in
|
||||||
if not operationgroup.on_acc.is_cash:
|
if not operationgroup.on_acc.is_cash:
|
||||||
Account.objects.filter(pk=operationgroup.on_acc.pk).update(
|
Account.objects.filter(pk=operationgroup.on_acc.pk).update(
|
||||||
balance = F('balance') + operationgroup.amount)
|
balance=F('balance') + operationgroup.amount)
|
||||||
operationgroup.on_acc.refresh_from_db()
|
operationgroup.on_acc.refresh_from_db()
|
||||||
if operationgroup.on_acc.balance < 0:
|
if operationgroup.on_acc.balance < 0:
|
||||||
if hasattr(operationgroup.on_acc, 'negative'):
|
if hasattr(operationgroup.on_acc, 'negative'):
|
||||||
|
@ -1070,21 +1112,21 @@ def kpsul_perform_operations(request):
|
||||||
operationgroup.on_acc.negative.save()
|
operationgroup.on_acc.negative.save()
|
||||||
else:
|
else:
|
||||||
negative = AccountNegative(
|
negative = AccountNegative(
|
||||||
account = operationgroup.on_acc, start = timezone.now())
|
account=operationgroup.on_acc, start=timezone.now())
|
||||||
negative.save()
|
negative.save()
|
||||||
elif (hasattr(operationgroup.on_acc, 'negative')
|
elif (hasattr(operationgroup.on_acc, 'negative') and
|
||||||
and not operationgroup.on_acc.negative.balance_offset):
|
not operationgroup.on_acc.negative.balance_offset):
|
||||||
operationgroup.on_acc.negative.delete()
|
operationgroup.on_acc.negative.delete()
|
||||||
|
|
||||||
# Updating checkout's balance
|
# Updating checkout's balance
|
||||||
if to_checkout_balance:
|
if to_checkout_balance:
|
||||||
Checkout.objects.filter(pk=operationgroup.checkout.pk).update(
|
Checkout.objects.filter(pk=operationgroup.checkout.pk).update(
|
||||||
balance = F('balance') + to_checkout_balance)
|
balance=F('balance') + to_checkout_balance)
|
||||||
|
|
||||||
# Saving addcost_for with new balance if there is one
|
# Saving addcost_for with new balance if there is one
|
||||||
if is_addcost and to_addcost_for_balance:
|
if is_addcost and to_addcost_for_balance:
|
||||||
Account.objects.filter(pk=addcost_for.pk).update(
|
Account.objects.filter(pk=addcost_for.pk).update(
|
||||||
balance = F('balance') + to_addcost_for_balance)
|
balance=F('balance') + to_addcost_for_balance)
|
||||||
|
|
||||||
# Saving operation group
|
# Saving operation group
|
||||||
operationgroup.save()
|
operationgroup.save()
|
||||||
|
@ -1099,7 +1141,7 @@ def kpsul_perform_operations(request):
|
||||||
# Updating articles stock
|
# Updating articles stock
|
||||||
for article in to_articles_stocks:
|
for article in to_articles_stocks:
|
||||||
Article.objects.filter(pk=article.pk).update(
|
Article.objects.filter(pk=article.pk).update(
|
||||||
stock = F('stock') + to_articles_stocks[article])
|
stock=F('stock') + to_articles_stocks[article])
|
||||||
|
|
||||||
# Websocket data
|
# Websocket data
|
||||||
websocket_data = {}
|
websocket_data = {}
|
||||||
|
@ -1111,17 +1153,20 @@ def kpsul_perform_operations(request):
|
||||||
'at': operationgroup.at,
|
'at': operationgroup.at,
|
||||||
'is_cof': operationgroup.is_cof,
|
'is_cof': operationgroup.is_cof,
|
||||||
'comment': operationgroup.comment,
|
'comment': operationgroup.comment,
|
||||||
'valid_by__trigramme': ( operationgroup.valid_by and
|
'valid_by__trigramme': (operationgroup.valid_by and
|
||||||
operationgroup.valid_by.trigramme or None),
|
operationgroup.valid_by.trigramme or None),
|
||||||
'on_acc__trigramme': operationgroup.on_acc.trigramme,
|
'on_acc__trigramme': operationgroup.on_acc.trigramme,
|
||||||
'opes': [],
|
'opes': [],
|
||||||
}]
|
}]
|
||||||
for operation in operations:
|
for operation in operations:
|
||||||
ope_data = {
|
ope_data = {
|
||||||
'id': operation.pk, 'type': operation.type, 'amount': operation.amount,
|
'id': operation.pk, 'type': operation.type,
|
||||||
|
'amount': operation.amount,
|
||||||
'addcost_amount': operation.addcost_amount,
|
'addcost_amount': operation.addcost_amount,
|
||||||
'addcost_for__trigramme': operation.addcost_for and addcost_for.trigramme or None,
|
'addcost_for__trigramme': (
|
||||||
'article__name': operation.article and operation.article.name or None,
|
operation.addcost_for and addcost_for.trigramme or None),
|
||||||
|
'article__name': (
|
||||||
|
operation.article and operation.article.name or None),
|
||||||
'article_nb': operation.article_nb,
|
'article_nb': operation.article_nb,
|
||||||
'group_id': operationgroup.pk,
|
'group_id': operationgroup.pk,
|
||||||
'canceled_by__trigramme': None, 'canceled_at': None,
|
'canceled_by__trigramme': None, 'canceled_at': None,
|
||||||
|
@ -1135,7 +1180,7 @@ def kpsul_perform_operations(request):
|
||||||
}]
|
}]
|
||||||
websocket_data['articles'] = []
|
websocket_data['articles'] = []
|
||||||
# Need refresh from db cause we used update on querysets
|
# Need refresh from db cause we used update on querysets
|
||||||
articles_pk = [ article.pk for article in to_articles_stocks]
|
articles_pk = [article.pk for article in to_articles_stocks]
|
||||||
articles = Article.objects.values('id', 'stock').filter(pk__in=articles_pk)
|
articles = Article.objects.values('id', 'stock').filter(pk__in=articles_pk)
|
||||||
for article in articles:
|
for article in articles:
|
||||||
websocket_data['articles'].append({
|
websocket_data['articles'].append({
|
||||||
|
@ -1145,6 +1190,7 @@ def kpsul_perform_operations(request):
|
||||||
consumers.KPsul.group_send('kfet.kpsul', websocket_data)
|
consumers.KPsul.group_send('kfet.kpsul', websocket_data)
|
||||||
return JsonResponse(data)
|
return JsonResponse(data)
|
||||||
|
|
||||||
|
|
||||||
@teamkfet_required
|
@teamkfet_required
|
||||||
def kpsul_cancel_operations(request):
|
def kpsul_cancel_operations(request):
|
||||||
# Pour la réponse
|
# Pour la réponse
|
||||||
|
@ -1393,7 +1439,8 @@ def history_json(request):
|
||||||
def kpsul_articles_data(request):
|
def kpsul_articles_data(request):
|
||||||
articles = (
|
articles = (
|
||||||
Article.objects
|
Article.objects
|
||||||
.values('id', 'name', 'price', 'stock', 'category_id', 'category__name')
|
.values('id', 'name', 'price', 'stock', 'category_id',
|
||||||
|
'category__name', 'category__has_addcost')
|
||||||
.filter(is_sold=True))
|
.filter(is_sold=True))
|
||||||
return JsonResponse({ 'articles': list(articles) })
|
return JsonResponse({ 'articles': list(articles) })
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue