forked from DGNum/gestioCOF
Merge remote-tracking branch 'origin/master' into Aufinal/fix_stock_ws
This commit is contained in:
commit
92fd94d1f9
9 changed files with 281 additions and 78 deletions
|
@ -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]
|
||||||
))
|
))
|
||||||
|
|
|
@ -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,
|
||||||
|
|
175
kfet/management/commands/createopes.py
Normal file
175
kfet/management/commands/createopes.py
Normal 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))
|
|
@ -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()
|
|
||||||
|
|
25
kfet/migrations/0048_default_datetime.py
Normal file
25
kfet/migrations/0048_default_datetime.py
Normal 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),
|
||||||
|
),
|
||||||
|
]
|
|
@ -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)
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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)
|
||||||
|
|
Loading…
Reference in a new issue