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:
Aurélien Delobelle 2017-04-05 15:52:15 +02:00
commit ebf948d042
10 changed files with 265 additions and 85 deletions

View file

@ -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
# ----- # -----

View 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'),
),
]

View file

@ -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)

View file

@ -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>

View file

@ -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 %}

View 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 %}

View 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 %}

View file

@ -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;

View file

@ -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()),

View file

@ -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) })