Merge remote-tracking branch 'origin/master' into Aufinal/fix_stock_ws

This commit is contained in:
Ludovic Stephan 2017-03-31 23:43:19 -03:00
commit 92fd94d1f9
9 changed files with 281 additions and 78 deletions

View file

@ -315,10 +315,11 @@ class SpectacleRevente(models.Model):
# Envoie un mail aux perdants # Envoie un mail aux perdants
for inscrit in inscrits: for inscrit in inscrits:
if inscrit != winner: if inscrit != winner:
context['acheteur'] = inscrit.user new_context = dict(context)
new_context['acheteur'] = inscrit.user
datatuple.append(( datatuple.append((
'bda-revente-loser', 'bda-revente-loser',
context, new_context,
settings.MAIL_DATA['revente']['FROM'], settings.MAIL_DATA['revente']['FROM'],
[inscrit.user.email] [inscrit.user.email]
)) ))

View file

@ -215,7 +215,7 @@ def _traitement_other(request, demande, redo):
proposals = proposals.items() proposals = proposals.items()
proposed_for = proposed_for.items() proposed_for = proposed_for.items()
return render(request, return render(request,
"gestiocof/traitement_demande_petit_cours_autre_niveau.html", "gestioncof/traitement_demande_petit_cours_autre_niveau.html",
{"demande": demande, {"demande": demande,
"unsatisfied": unsatisfied, "unsatisfied": unsatisfied,
"proposals": proposals, "proposals": proposals,

View file

@ -0,0 +1,175 @@
"""
Crée des opérations aléatoires réparties sur une période de temps spécifiée
"""
import random
from datetime import timedelta
from decimal import Decimal
from django.utils import timezone
from django.core.management.base import BaseCommand
from kfet.models import (Account, Article, OperationGroup, Operation,
Checkout, Transfer, TransferGroup)
class Command(BaseCommand):
help = "Crée des opérations réparties uniformément sur une période de temps"
def add_arguments(self, parser):
# Nombre d'opérations à créer
parser.add_argument('opes', type=int,
help='Number of opegroups to create')
# Période sur laquelle créer (depuis num_days avant maintenant)
parser.add_argument('days', type=int,
help='Period in which to create opegroups')
# Optionnel : nombre de transfert à créer (défaut 0)
parser.add_argument('--transfers', type=int, default=0,
help='Number of transfers to create (default 0)')
def handle(self, *args, **options):
self.stdout.write("Génération d'opérations")
# Output log vars
opes_created = 0
purchases = 0
transfers = 0
num_ops = options['opes']
num_transfers = options['transfers']
# Convert to seconds
time = options['days'] * 24 * 3600
checkout = Checkout.objects.first()
articles = Article.objects.all()
accounts = Account.objects.exclude(trigramme='LIQ')
liq_account = Account.objects.get(trigramme='LIQ')
try:
con_account = Account.objects.get(
cofprofile__user__first_name='Assurancetourix'
)
except Account.DoesNotExist:
con_account = random.choice(accounts)
for i in range(num_ops):
# Randomly pick account
if random.random() > 0.25:
account = random.choice(accounts)
else:
account = liq_account
# Randomly pick time
at = timezone.now() - timedelta(
seconds=random.randint(0, time))
# Majoration sur compte 'concert'
if random.random() < 0.2:
addcost = True
addcost_for = con_account
addcost_amount = Decimal('0.5')
else:
addcost = False
# Initialize opegroup amount
amount = Decimal('0')
opegroup = OperationGroup.objects.create(
on_acc=account,
checkout=checkout,
at=at,
is_cof=account.cofprofile.is_cof
)
# Generating operations
ope_list = []
for j in range(random.randint(1, 4)):
# Operation type
typevar = random.random()
# 0.1 probability to have a charge
if typevar > 0.9 and account != liq_account:
ope = Operation(
group=opegroup,
type=Operation.DEPOSIT,
is_checkout=(random.random() > 0.2),
amount=Decimal(random.randint(1, 99)/10)
)
# 0.1 probability to have a withdrawal
elif typevar > 0.8 and account != liq_account:
ope = Operation(
group=opegroup,
type=Operation.WITHDRAW,
is_checkout=(random.random() > 0.2),
amount=-Decimal(random.randint(1, 99)/10)
)
else:
article = random.choice(articles)
nb = random.randint(1, 5)
ope = Operation(
group=opegroup,
type=Operation.PURCHASE,
amount=-article.price*nb,
article=article,
article_nb=nb
)
purchases += 1
if addcost:
ope.addcost_for = addcost_for
ope.addcost_amount = addcost_amount * nb
ope.amount -= ope.addcost_amount
ope_list.append(ope)
amount += ope.amount
Operation.objects.bulk_create(ope_list)
opes_created += len(ope_list)
opegroup.amount = amount
opegroup.save()
# Transfer generation
for i in range(num_transfers):
# Randomly pick time
at = timezone.now() - timedelta(
seconds=random.randint(0, time))
# Choose whether to have a comment
if random.random() > 0.5:
comment = "placeholder comment"
else:
comment = ""
transfergroup = TransferGroup.objects.create(
at=at,
comment=comment,
valid_by=random.choice(accounts)
)
# Randomly generate transfer
transfer_list = []
for i in range(random.randint(1, 4)):
transfer_list.append(Transfer(
group=transfergroup,
from_acc=random.choice(accounts),
to_acc=random.choice(accounts),
amount=Decimal(random.randint(1, 99)/10)
))
Transfer.objects.bulk_create(transfer_list)
transfers += len(transfer_list)
self.stdout.write(
"- {:d} opérations créées dont {:d} commandes d'articles"
.format(opes_created, purchases))
if transfers:
self.stdout.write("- {:d} transferts créés"
.format(transfers))

View file

@ -5,15 +5,15 @@ Crée des utilisateurs, des articles et des opérations aléatoires
import os import os
import random import random
from datetime import timedelta from datetime import timedelta
from decimal import Decimal
from django.utils import timezone from django.utils import timezone
from django.contrib.auth.models import User, Group, Permission, ContentType from django.contrib.auth.models import User, Group, Permission, ContentType
from django.core.management import call_command
from gestioncof.management.base import MyBaseCommand from gestioncof.management.base import MyBaseCommand
from gestioncof.models import CofProfile from gestioncof.models import CofProfile
from kfet.models import (Account, Article, OperationGroup, Operation, from kfet.models import (Account, Checkout, CheckoutStatement, Supplier,
Checkout, CheckoutStatement) SupplierArticle, Article)
# Où sont stockés les fichiers json # Où sont stockés les fichiers json
DATA_DIR = os.path.join(os.path.dirname(os.path.dirname(__file__)), DATA_DIR = os.path.join(os.path.dirname(os.path.dirname(__file__)),
@ -126,65 +126,24 @@ class Command(MyBaseCommand):
amount_error=0 amount_error=0
) )
# ---
# Fournisseur
# ---
supplier, created = Supplier.objects.get_or_create(name="Panoramix")
if created:
articles = random.sample(list(Article.objects.all()), 40)
to_create = []
for article in articles:
to_create.append(SupplierArticle(
supplier=supplier,
article=article
))
SupplierArticle.objects.bulk_create(to_create)
# --- # ---
# Opérations # Opérations
# --- # ---
self.stdout.write("Génération d'opérations") call_command('createopes', '100', '7', '--transfers=20')
articles = Article.objects.all()
accounts = Account.objects.exclude(trigramme='LIQ')
num_op = 100
# Operations are put uniformly over the span of a week
past_date = 3600*24*7
for i in range(num_op):
if random.random() > 0.25:
account = random.choice(accounts)
else:
account = liq_account
amount = Decimal('0')
at = timezone.now() - timedelta(
seconds=random.randint(0, past_date))
opegroup = OperationGroup(
on_acc=account,
checkout=checkout,
at=at,
is_cof=account.cofprofile.is_cof)
opegroup.save()
for j in range(random.randint(1, 4)):
typevar = random.random()
if typevar > 0.9 and account != liq_account:
ope = Operation(
group=opegroup,
type=Operation.DEPOSIT,
amount=Decimal(random.randint(1, 99)/10,)
)
elif typevar > 0.8 and account != liq_account:
ope = Operation(
group=opegroup,
type=Operation.WITHDRAW,
amount=-Decimal(random.randint(1, 99)/10,)
)
else:
article = random.choice(articles)
nb = random.randint(1, 5)
ope = Operation(
group=opegroup,
type=Operation.PURCHASE,
amount=-article.price*nb,
article=article,
article_nb=nb
)
ope.save()
amount += ope.amount
opegroup.amount = amount
opegroup.save()

View file

@ -0,0 +1,25 @@
# -*- coding: utf-8 -*-
from __future__ import unicode_literals
from django.db import migrations, models
import django.utils.timezone
class Migration(migrations.Migration):
dependencies = [
('kfet', '0047_auto_20170104_1528'),
]
operations = [
migrations.AlterField(
model_name='operationgroup',
name='at',
field=models.DateTimeField(default=django.utils.timezone.now),
),
migrations.AlterField(
model_name='transfergroup',
name='at',
field=models.DateTimeField(default=django.utils.timezone.now),
),
]

View file

@ -466,7 +466,7 @@ class OrderArticle(models.Model):
quantity_received = models.IntegerField(default = 0) quantity_received = models.IntegerField(default = 0)
class TransferGroup(models.Model): class TransferGroup(models.Model):
at = models.DateTimeField(auto_now_add = True) at = models.DateTimeField(default=timezone.now)
# Optional # Optional
comment = models.CharField( comment = models.CharField(
max_length = 255, max_length = 255,
@ -502,7 +502,7 @@ class OperationGroup(models.Model):
checkout = models.ForeignKey( checkout = models.ForeignKey(
Checkout, on_delete = models.PROTECT, Checkout, on_delete = models.PROTECT,
related_name = "opesgroup") related_name = "opesgroup")
at = models.DateTimeField(auto_now_add = True) at = models.DateTimeField(default=timezone.now)
amount = models.DecimalField( amount = models.DecimalField(
max_digits = 6, decimal_places = 2, max_digits = 6, decimal_places = 2,
default = 0) default = 0)

View file

@ -27,6 +27,53 @@ $(document).ready(function() {
} }
}); });
/*
* Generic Websocket class and k-psul ws instanciation
*/
class KfetWebsocket {
static get defaults() {
return {"relative_url": "", "default_msg": {}, "handlers": []};
}
constructor(data) {
$.extend(this, this.constructor.defaults, data);
}
get url() {
var websocket_protocol = window.location.protocol == 'https:' ? 'wss' : 'ws';
var location_host = window.location.host;
var location_url = window.location.pathname.startsWith('/gestion/') ? location_host + '/gestion' : location_host;
return websocket_protocol+"://" + location_url + this.relative_url ;
}
add_handler(handler) {
if (!this.socket)
this.listen();
this.handlers.push(handler);
}
listen() {
var that = this;
this.socket = new ReconnectingWebSocket(this.url);
this.socket.onmessage = function(e) {
var data = $.extend({}, that.default_msg, JSON.parse(e.data));
for (let handler of that.handlers) {
handler(data);
}
}
}
}
var OperationWebSocket = new KfetWebsocket({
'relative_url': '/ws/k-fet/k-psul/',
'default_msg': {'opegroups':[],'opes':[],'checkouts':[],'articles':[]},
});
function dateUTCToParis(date) { function dateUTCToParis(date) {
return moment.tz(date, 'UTC').tz('Europe/Paris'); return moment.tz(date, 'UTC').tz('Europe/Paris');
} }
@ -86,6 +133,9 @@ function getErrorsHtml(data) {
content += '<li>Montant invalide</li>'; content += '<li>Montant invalide</li>';
content += '</ul>'; content += '</ul>';
} }
if ('account' in data['errors']) {
content += data['errors']['account'];
}
return content; return content;
} }

View file

@ -12,7 +12,6 @@
<script type="text/javascript" src="{% static 'kfet/js/moment.js' %}"></script> <script type="text/javascript" src="{% static 'kfet/js/moment.js' %}"></script>
<script type="text/javascript" src="{% static 'kfet/js/moment-fr.js' %}"></script> <script type="text/javascript" src="{% static 'kfet/js/moment-fr.js' %}"></script>
<script type="text/javascript" src="{% static 'kfet/js/moment-timezone-with-data-2010-2020.js' %}"></script> <script type="text/javascript" src="{% static 'kfet/js/moment-timezone-with-data-2010-2020.js' %}"></script>
<script type="text/javascript" src="{% static 'kfet/js/kfet.js' %}"></script>
<script type="text/javascript" src="{% static 'kfet/js/history.js' %}"></script> <script type="text/javascript" src="{% static 'kfet/js/history.js' %}"></script>
{% endblock %} {% endblock %}
@ -1321,15 +1320,7 @@ $(document).ready(function() {
// Synchronization // Synchronization
// ----- // -----
websocket_msg_default = {'opegroups':[],'opes':[],'checkouts':[],'articles':[]} OperationWebSocket.add_handler(function(data) {
var websocket_protocol = window.location.protocol == 'https:' ? 'wss' : 'ws';
var location_host = window.location.host;
var location_url = window.location.pathname.startsWith('/gestion/') ? location_host + '/gestion' : location_host;
socket = new ReconnectingWebSocket(websocket_protocol+"://" + location_url + "/ws/k-fet/k-psul/");
socket.onmessage = function(e) {
data = $.extend({}, websocket_msg_default, JSON.parse(e.data));
for (var i=0; i<data['opegroups'].length; i++) { for (var i=0; i<data['opegroups'].length; i++) {
if (data['opegroups'][i]['add']) { if (data['opegroups'][i]['add']) {
khistory.addOpeGroup(data['opegroups'][i]); khistory.addOpeGroup(data['opegroups'][i]);
@ -1369,7 +1360,7 @@ $(document).ready(function() {
settings['addcost_amount'] = parseFloat(data['addcost']['amount']); settings['addcost_amount'] = parseFloat(data['addcost']['amount']);
displayAddcost(); displayAddcost();
} }
} });
// ----- // -----
// General // General

View file

@ -1041,7 +1041,9 @@ def kpsul_perform_operations(request):
operationgroup.comment = operationgroup.comment.strip() operationgroup.comment = operationgroup.comment.strip()
if not operationgroup.comment: if not operationgroup.comment:
data['errors']['need_comment'] = True data['errors']['need_comment'] = True
return JsonResponse(data, status=400)
if data['errors']:
return JsonResponse(data, status=400)
if stop or not request.user.has_perms(required_perms): if stop or not request.user.has_perms(required_perms):
missing_perms = get_missing_perms(required_perms, request.user) missing_perms = get_missing_perms(required_perms, request.user)