forked from DGNum/gestioCOF
Merge branch 'Aufinal/transferts_historique' of git.eleves.ens.fr:cof-geek/gestioCOF into Aufinal/transferts_historique
This commit is contained in:
commit
8895daff6a
7 changed files with 313 additions and 251 deletions
|
@ -40,6 +40,11 @@
|
||||||
width:90px;
|
width:90px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#history .opegroup .info {
|
||||||
|
text-align:center;
|
||||||
|
width:145px;
|
||||||
|
}
|
||||||
|
|
||||||
#history .opegroup .valid_by {
|
#history .opegroup .valid_by {
|
||||||
padding-left:20px
|
padding-left:20px
|
||||||
}
|
}
|
||||||
|
@ -67,6 +72,10 @@
|
||||||
text-align:right;
|
text-align:right;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#history .ope .glyphicon {
|
||||||
|
padding-left:15px;
|
||||||
|
}
|
||||||
|
|
||||||
#history .ope .infos2 {
|
#history .ope .infos2 {
|
||||||
padding-left:15px;
|
padding-left:15px;
|
||||||
}
|
}
|
||||||
|
|
|
@ -15,10 +15,18 @@ function KHistory(options={}) {
|
||||||
|
|
||||||
var trigramme = opegroup['on_acc_trigramme'];
|
var trigramme = opegroup['on_acc_trigramme'];
|
||||||
var is_cof = opegroup['is_cof'];
|
var is_cof = opegroup['is_cof'];
|
||||||
for (var i=0; i<opegroup['opes'].length; i++) {
|
if (opegroup['type'] == 'opegroup') {
|
||||||
var $ope = this._opeHtml(opegroup['opes'][i], is_cof, trigramme);
|
for (var i=0; i<opegroup['opes'].length; i++) {
|
||||||
$ope.data('opegroup', opegroup['id']);
|
var $ope = this._opeHtml(opegroup['opes'][i], is_cof, trigramme);
|
||||||
$opegroup.after($ope);
|
$ope.data('opegroup', opegroup['id']);
|
||||||
|
$opegroup.after($ope);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
for (var i=0; i<opegroup['opes'].length; i++) {
|
||||||
|
var $transfer = this._transferHtml(opegroup['opes'][i]);
|
||||||
|
$transfer.data('transfergroup', opegroup['id']);
|
||||||
|
$opegroup.after($transfer);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -41,7 +49,8 @@ function KHistory(options={}) {
|
||||||
}
|
}
|
||||||
|
|
||||||
$ope_html
|
$ope_html
|
||||||
.data('ope', ope['id'])
|
.data('type', 'ope')
|
||||||
|
.data('id', ope['id'])
|
||||||
.find('.amount').text(amount).end()
|
.find('.amount').text(amount).end()
|
||||||
.find('.infos1').text(infos1).end()
|
.find('.infos1').text(infos1).end()
|
||||||
.find('.infos2').text(infos2).end();
|
.find('.infos2').text(infos2).end();
|
||||||
|
@ -58,6 +67,25 @@ function KHistory(options={}) {
|
||||||
return $ope_html;
|
return $ope_html;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
this._transferHtml = function(transfer) {
|
||||||
|
var $transfer_html = $(this.template_transfer);
|
||||||
|
var parsed_amount = parseFloat(transfer['amount']);
|
||||||
|
var amount = parsed_amount.toFixed(2) + '€';
|
||||||
|
|
||||||
|
$transfer_html
|
||||||
|
.data('type', 'transfer')
|
||||||
|
.data('id', transfer['id'])
|
||||||
|
.find('.amount').text(amount).end()
|
||||||
|
.find('.infos1').text(transfer['from_acc']).end()
|
||||||
|
.find('.infos2').text(transfer['to_acc']).end();
|
||||||
|
|
||||||
|
if (transfer['canceled_at'])
|
||||||
|
this.cancelOpe(transfer, $transfer_html);
|
||||||
|
|
||||||
|
return $transfer_html ;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
this.cancelOpe = function(ope, $ope = null) {
|
this.cancelOpe = function(ope, $ope = null) {
|
||||||
if (!$ope)
|
if (!$ope)
|
||||||
$ope = this.findOpe(ope['id']);
|
$ope = this.findOpe(ope['id']);
|
||||||
|
@ -72,23 +100,36 @@ function KHistory(options={}) {
|
||||||
}
|
}
|
||||||
|
|
||||||
this._opeGroupHtml = function(opegroup) {
|
this._opeGroupHtml = function(opegroup) {
|
||||||
var $opegroup_html = $(this.template_opegroup);
|
|
||||||
|
var type = opegroup['type'];
|
||||||
|
|
||||||
|
|
||||||
|
if (type == 'opegroup') {
|
||||||
|
var $opegroup_html = $(this.template_opegroup);
|
||||||
|
var trigramme = opegroup['on_acc__trigramme'];
|
||||||
|
var amount = amountDisplay(
|
||||||
|
parseFloat(opegroup['amount']), opegroup['is_cof'], trigramme);
|
||||||
|
} else {
|
||||||
|
var $opegroup_html = $(this.template_transfergroup);
|
||||||
|
var trigramme = '';
|
||||||
|
var amount = '' ;
|
||||||
|
}
|
||||||
|
|
||||||
var at = dateUTCToParis(opegroup['at']).format('HH:mm:ss');
|
var at = dateUTCToParis(opegroup['at']).format('HH:mm:ss');
|
||||||
var trigramme = opegroup['on_acc__trigramme'];
|
|
||||||
var amount = amountDisplay(
|
|
||||||
parseFloat(opegroup['amount']), opegroup['is_cof'], trigramme);
|
|
||||||
var comment = opegroup['comment'] || '';
|
var comment = opegroup['comment'] || '';
|
||||||
|
|
||||||
$opegroup_html
|
$opegroup_html
|
||||||
.data('opegroup', opegroup['id'])
|
.data('type', type)
|
||||||
|
.data('id', opegroup['id'])
|
||||||
.find('.time').text(at).end()
|
.find('.time').text(at).end()
|
||||||
|
.find('.trigramme').text(trigramme).end()
|
||||||
|
.find('.info').text("Transferts").end()
|
||||||
.find('.amount').text(amount).end()
|
.find('.amount').text(amount).end()
|
||||||
.find('.comment').text(comment).end()
|
.find('.comment').text(comment).end();
|
||||||
.find('.trigramme').text(trigramme).end();
|
|
||||||
|
|
||||||
if (!this.display_trigramme)
|
if (!this.display_trigramme)
|
||||||
$opegroup_html.find('.trigramme').remove();
|
$opegroup_html.find('.trigramme').remove();
|
||||||
|
$opegroup_html.find('.info').remove();
|
||||||
|
|
||||||
if (opegroup['valid_by__trigramme'])
|
if (opegroup['valid_by__trigramme'])
|
||||||
$opegroup_html.find('.valid_by').text('Par '+opegroup['valid_by__trigramme']);
|
$opegroup_html.find('.valid_by').text('Par '+opegroup['valid_by__trigramme']);
|
||||||
|
@ -114,9 +155,9 @@ function KHistory(options={}) {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
this.findOpe = function(id) {
|
this.findOpe = function(id, type) {
|
||||||
return this.$container.find('.ope').filter(function() {
|
return this.$container.find('.ope').filter(function() {
|
||||||
return $(this).data('ope') == id
|
return ($(this).data('id') == id && $(this).data('type') == type)
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -134,6 +175,8 @@ KHistory.default_options = {
|
||||||
container: '#history',
|
container: '#history',
|
||||||
template_day: '<div class="day"></div>',
|
template_day: '<div class="day"></div>',
|
||||||
template_opegroup: '<div class="opegroup"><span class="time"></span><span class="trigramme"></span><span class="amount"></span><span class="valid_by"></span><span class="comment"></span></div>',
|
template_opegroup: '<div class="opegroup"><span class="time"></span><span class="trigramme"></span><span class="amount"></span><span class="valid_by"></span><span class="comment"></span></div>',
|
||||||
|
template_transfergroup: '<div class="opegroup"><span class="time"></span><span class="info"></span><span class="valid_by"></span><span class="comment"></span></div>',
|
||||||
template_ope: '<div class="ope"><span class="amount"></span><span class="infos1"></span><span class="infos2"></span><span class="addcost"></span><span class="canceled"></span></div>',
|
template_ope: '<div class="ope"><span class="amount"></span><span class="infos1"></span><span class="infos2"></span><span class="addcost"></span><span class="canceled"></span></div>',
|
||||||
|
template_transfer: '<div class="ope"><span class="amount"></span><span class="infos1"></span><span class="glyphicon glyphicon-arrow-right"></span><span class="infos2"></span><span class="canceled"></span></div>',
|
||||||
display_trigramme: true,
|
display_trigramme: true,
|
||||||
}
|
}
|
||||||
|
|
|
@ -138,3 +138,8 @@ function requestAuth(data, callback, focus_next = null) {
|
||||||
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
String.prototype.pluralize = function(count, irreg_plural = false) {
|
||||||
|
plural = irreg_plural ? irreg_plural : this + 's' ;
|
||||||
|
return (count==1 ? this : plural) ;
|
||||||
|
}
|
||||||
|
|
|
@ -62,6 +62,8 @@
|
||||||
$(document).ready(function() {
|
$(document).ready(function() {
|
||||||
settings = { 'subvention_cof': parseFloat({{ settings.subvention_cof|unlocalize }})}
|
settings = { 'subvention_cof': parseFloat({{ settings.subvention_cof|unlocalize }})}
|
||||||
|
|
||||||
|
lock = 0 ;
|
||||||
|
|
||||||
khistory = new KHistory();
|
khistory = new KHistory();
|
||||||
|
|
||||||
var $from_date = $('#from_date');
|
var $from_date = $('#from_date');
|
||||||
|
@ -142,9 +144,10 @@ $(document).ready(function() {
|
||||||
selected: function(e, ui) {
|
selected: function(e, ui) {
|
||||||
$(ui.selected).each(function() {
|
$(ui.selected).each(function() {
|
||||||
if ($(this).hasClass('opegroup')) {
|
if ($(this).hasClass('opegroup')) {
|
||||||
var opegroup = $(this).data('opegroup');
|
var type = $(this).data('type');
|
||||||
|
var id = $(this).data('id');
|
||||||
$(this).siblings('.ope').filter(function() {
|
$(this).siblings('.ope').filter(function() {
|
||||||
return $(this).data('opegroup') == opegroup
|
return $(this).data(type) == id
|
||||||
}).addClass('ui-selected');
|
}).addClass('ui-selected');
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
@ -156,7 +159,7 @@ $(document).ready(function() {
|
||||||
// DEL (Suppr)
|
// DEL (Suppr)
|
||||||
var opes_to_cancel = [];
|
var opes_to_cancel = [];
|
||||||
khistory.$container.find('.ope.ui-selected').each(function () {
|
khistory.$container.find('.ope.ui-selected').each(function () {
|
||||||
opes_to_cancel.push($(this).data('ope'));
|
opes_to_cancel.push($(this).data('type')+' '+$(this).data('id'));
|
||||||
});
|
});
|
||||||
if (opes_to_cancel.length > 0)
|
if (opes_to_cancel.length > 0)
|
||||||
confirmCancel(opes_to_cancel);
|
confirmCancel(opes_to_cancel);
|
||||||
|
@ -165,7 +168,10 @@ $(document).ready(function() {
|
||||||
|
|
||||||
function confirmCancel(opes_to_cancel) {
|
function confirmCancel(opes_to_cancel) {
|
||||||
var nb = opes_to_cancel.length;
|
var nb = opes_to_cancel.length;
|
||||||
var content = nb+" opérations vont être annulées";
|
var content = nb+' opération'.pluralize(nb)
|
||||||
|
+' va'.pluralize(nb, ' vont')
|
||||||
|
+ ' être'
|
||||||
|
+ ' annulée'.pluralize(nb);
|
||||||
$.confirm({
|
$.confirm({
|
||||||
title: 'Confirmation',
|
title: 'Confirmation',
|
||||||
content: content,
|
content: content,
|
||||||
|
@ -179,50 +185,10 @@ $(document).ready(function() {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function requestAuth(data, callback) {
|
|
||||||
var content = getErrorsHtml(data);
|
|
||||||
content += '<input type="password" name="password" autofocus>',
|
|
||||||
$.confirm({
|
|
||||||
title: 'Authentification requise',
|
|
||||||
content: content,
|
|
||||||
backgroundDismiss: true,
|
|
||||||
animation:'top',
|
|
||||||
closeAnimation:'bottom',
|
|
||||||
keyboardEnabled: true,
|
|
||||||
confirm: function() {
|
|
||||||
var password = this.$content.find('input').val();
|
|
||||||
callback(password);
|
|
||||||
},
|
|
||||||
onOpen: function() {
|
|
||||||
var that = this;
|
|
||||||
this.$content.find('input').on('keypress', function(e) {
|
|
||||||
if (e.keyCode == 13)
|
|
||||||
that.$confirmButton.click();
|
|
||||||
});
|
|
||||||
},
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
function getErrorsHtml(data) {
|
|
||||||
var content = '';
|
|
||||||
if ('missing_perms' in data['errors']) {
|
|
||||||
content += 'Permissions manquantes';
|
|
||||||
content += '<ul>';
|
|
||||||
for (var i=0; i<data['errors']['missing_perms'].length; i++)
|
|
||||||
content += '<li>'+data['errors']['missing_perms'][i]+'</li>';
|
|
||||||
content += '</ul>';
|
|
||||||
}
|
|
||||||
if ('negative' in data['errors']) {
|
|
||||||
var url_base = "{% url 'kfet.account.update' LIQ}";
|
|
||||||
url_base = base_url(0, url_base.length-8);
|
|
||||||
for (var i=0; i<data['errors']['negative'].length; i++) {
|
|
||||||
content += '<a class="btn btn-primary" href="'+url_base+data['errors']['negative'][i]+'/edit" target="_blank">Autorisation de négatif requise pour '+data['errors']['negative'][i]+'</a>';
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return content;
|
|
||||||
}
|
|
||||||
|
|
||||||
function cancelOperations(opes_array, password = '') {
|
function cancelOperations(opes_array, password = '') {
|
||||||
|
if (lock == 1)
|
||||||
|
return false
|
||||||
|
lock = 1 ;
|
||||||
var data = { 'operations' : opes_array }
|
var data = { 'operations' : opes_array }
|
||||||
$.ajax({
|
$.ajax({
|
||||||
dataType: "json",
|
dataType: "json",
|
||||||
|
@ -238,6 +204,7 @@ $(document).ready(function() {
|
||||||
})
|
})
|
||||||
.done(function(data) {
|
.done(function(data) {
|
||||||
khistory.$container.find('.ui-selected').removeClass('ui-selected');
|
khistory.$container.find('.ui-selected').removeClass('ui-selected');
|
||||||
|
lock = 0 ;
|
||||||
})
|
})
|
||||||
.fail(function($xhr) {
|
.fail(function($xhr) {
|
||||||
var data = $xhr.responseJSON;
|
var data = $xhr.responseJSON;
|
||||||
|
@ -251,6 +218,7 @@ $(document).ready(function() {
|
||||||
displayErrors(getErrorsHtml(data));
|
displayErrors(getErrorsHtml(data));
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
lock = 0 ;
|
||||||
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,7 +6,11 @@
|
||||||
<script type="text/javascript" src="{% static 'kfet/js/js.cookie.js' %}"></script>
|
<script type="text/javascript" src="{% static 'kfet/js/js.cookie.js' %}"></script>
|
||||||
<script type="text/javascript" src="{% static 'kfet/js/jquery-ui.min.js' %}"></script>
|
<script type="text/javascript" src="{% static 'kfet/js/jquery-ui.min.js' %}"></script>
|
||||||
<script type="text/javascript" src="{% static 'kfet/js/jquery-confirm.js' %}"></script>
|
<script type="text/javascript" src="{% static 'kfet/js/jquery-confirm.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-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/kfet.js' %}"></script>
|
||||||
|
<script type="text/javascript" src="{% static 'kfet/js/history.js' %}"></script>
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
||||||
{% block title %}Transferts{% endblock %}
|
{% block title %}Transferts{% endblock %}
|
||||||
|
@ -31,22 +35,7 @@
|
||||||
<div class="content-right">
|
<div class="content-right">
|
||||||
<div class="content-right-block">
|
<div class="content-right-block">
|
||||||
<h2>Liste des transferts</h2>
|
<h2>Liste des transferts</h2>
|
||||||
<div id="history">
|
<table id="history" class="table">
|
||||||
{% for transfergroup in transfergroups %}
|
|
||||||
<div class="opegroup transfergroup" data-transfergroup="{{ transfergroup.pk }}">
|
|
||||||
<span>{{ transfergroup.at }}</span>
|
|
||||||
<span>{{ transfergroup.valid_by.trigramme }}</span>
|
|
||||||
<span>{{ transfergroup.comment }}</span>
|
|
||||||
</div>
|
|
||||||
{% for transfer in transfergroup.transfers.all %}
|
|
||||||
<div class="ope transfer{% if transfer.canceled_at %} canceled{% endif %}" data-transfer="{{ transfer.pk }}" data-transfergroup="{{ transfergroup.pk }}">
|
|
||||||
<span class="amount">{{ transfer.amount }} €</span>
|
|
||||||
<span class="from_acc">{{ transfer.from_acc.trigramme }}</span>
|
|
||||||
<span class="glyphicon glyphicon-arrow-right"></span>
|
|
||||||
<span class="to_acc">{{ transfer.to_acc.trigramme }}</span>
|
|
||||||
</div>
|
|
||||||
{% endfor %}
|
|
||||||
{% endfor %}
|
|
||||||
</table>
|
</table>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -70,15 +59,80 @@ $(document).ready(function() {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
khistory = new KHistory({
|
||||||
|
display_trigramme: false,
|
||||||
|
});
|
||||||
|
|
||||||
|
function getHistory() {
|
||||||
|
var data = {'transfersonly': true};
|
||||||
|
|
||||||
function cancelTransfers(transfers_array, password = '') {
|
|
||||||
if (lock == 1)
|
|
||||||
return false
|
|
||||||
lock = 1;
|
|
||||||
var data = { 'transfers' : transfers_array }
|
|
||||||
$.ajax({
|
$.ajax({
|
||||||
dataType: "json",
|
dataType: "json",
|
||||||
url : "{% url 'kfet.transfers.cancel' %}",
|
url : "{% url 'kfet.history.json' %}",
|
||||||
|
method : "POST",
|
||||||
|
data : data,
|
||||||
|
})
|
||||||
|
.done(function(data) {
|
||||||
|
for (var i=0; i<data['opegroups'].length; i++) {
|
||||||
|
khistory.addOpeGroup(data['opegroups'][i]);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
khistory.$container.selectable({
|
||||||
|
filter: 'div.opegroup, div.ope',
|
||||||
|
selected: function(e, ui) {
|
||||||
|
$(ui.selected).each(function() {
|
||||||
|
if ($(this).hasClass('opegroup')) {
|
||||||
|
var type = $(this).data('type');
|
||||||
|
var id = $(this).data('id');
|
||||||
|
$(this).siblings('.ope').filter(function() {
|
||||||
|
return $(this).data(type) == id
|
||||||
|
}).addClass('ui-selected');
|
||||||
|
}
|
||||||
|
});
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
$(document).on('keydown', function (e) {
|
||||||
|
if (e.keyCode == 46) {
|
||||||
|
// DEL (Suppr)
|
||||||
|
var opes_to_cancel = [];
|
||||||
|
khistory.$container.find('.ope.ui-selected').each(function () {
|
||||||
|
opes_to_cancel.push($(this).data('type')+' '+$(this).data('id'));
|
||||||
|
});
|
||||||
|
if (opes_to_cancel.length > 0)
|
||||||
|
confirmCancel(opes_to_cancel);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
function confirmCancel(opes_to_cancel) {
|
||||||
|
var nb = opes_to_cancel.length;
|
||||||
|
var content = nb+' opération'.pluralize(nb)
|
||||||
|
+' va'.pluralize(nb, ' vont')
|
||||||
|
+ ' être'
|
||||||
|
+ ' annulée'.pluralize(nb);
|
||||||
|
$.confirm({
|
||||||
|
title: 'Confirmation',
|
||||||
|
content: content,
|
||||||
|
backgroundDismiss: true,
|
||||||
|
animation: 'top',
|
||||||
|
closeAnimation: 'bottom',
|
||||||
|
keyboardEnabled: true,
|
||||||
|
confirm: function() {
|
||||||
|
cancelOperations(opes_to_cancel);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function cancelOperations(opes_array, password = '') {
|
||||||
|
if (lock == 1)
|
||||||
|
return false
|
||||||
|
lock = 1 ;
|
||||||
|
var data = { 'operations' : opes_array }
|
||||||
|
$.ajax({
|
||||||
|
dataType: "json",
|
||||||
|
url : "{% url 'kfet.kpsul.cancel_operations' %}",
|
||||||
method : "POST",
|
method : "POST",
|
||||||
data : data,
|
data : data,
|
||||||
beforeSend: function ($xhr) {
|
beforeSend: function ($xhr) {
|
||||||
|
@ -89,11 +143,7 @@ $(document).ready(function() {
|
||||||
|
|
||||||
})
|
})
|
||||||
.done(function(data) {
|
.done(function(data) {
|
||||||
for (var i=0; i<data['canceled'].length; i++) {
|
khistory.$container.find('.ui-selected').removeClass('ui-selected');
|
||||||
$('#history').find('.transfer[data-transfer='+data['canceled'][i]+']')
|
|
||||||
.addClass('canceled');
|
|
||||||
}
|
|
||||||
$('#history').find('.ui-selected').removeClass('ui-selected');
|
|
||||||
lock = 0;
|
lock = 0;
|
||||||
})
|
})
|
||||||
.fail(function($xhr) {
|
.fail(function($xhr) {
|
||||||
|
@ -101,7 +151,7 @@ $(document).ready(function() {
|
||||||
switch ($xhr.status) {
|
switch ($xhr.status) {
|
||||||
case 403:
|
case 403:
|
||||||
requestAuth(data, function(password) {
|
requestAuth(data, function(password) {
|
||||||
cancelTransfers(transfers_array, password);
|
cancelOperations(opes_array, password);
|
||||||
});
|
});
|
||||||
break;
|
break;
|
||||||
case 400:
|
case 400:
|
||||||
|
@ -112,31 +162,7 @@ $(document).ready(function() {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
$('#history').selectable({
|
getHistory();
|
||||||
filter: 'div.transfergroup, div.transfer',
|
|
||||||
selected: function(e, ui) {
|
|
||||||
$(ui.selected).each(function() {
|
|
||||||
if ($(this).hasClass('transfergroup')) {
|
|
||||||
var transfergroup = $(this).attr('data-transfergroup');
|
|
||||||
$(this).siblings('.ope').filter(function() {
|
|
||||||
return $(this).attr('data-transfergroup') == transfergroup
|
|
||||||
}).addClass('ui-selected');
|
|
||||||
}
|
|
||||||
});
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
$(document).on('keydown', function (e) {
|
|
||||||
if (e.keyCode == 46) {
|
|
||||||
// DEL (Suppr)
|
|
||||||
var transfers_to_cancel = [];
|
|
||||||
$('#history').find('.transfer.ui-selected').each(function () {
|
|
||||||
transfers_to_cancel.push($(this).attr('data-transfer'));
|
|
||||||
});
|
|
||||||
if (transfers_to_cancel.length > 0)
|
|
||||||
cancelTransfers(transfers_to_cancel);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
@ -178,8 +178,6 @@ urlpatterns = [
|
||||||
name='kfet.transfers.create'),
|
name='kfet.transfers.create'),
|
||||||
url(r'^transfers/perform$', views.perform_transfers,
|
url(r'^transfers/perform$', views.perform_transfers,
|
||||||
name='kfet.transfers.perform'),
|
name='kfet.transfers.perform'),
|
||||||
url(r'^transfers/cancel$', views.cancel_transfers,
|
|
||||||
name='kfet.transfers.cancel'),
|
|
||||||
|
|
||||||
# -----
|
# -----
|
||||||
# Inventories urls
|
# Inventories urls
|
||||||
|
|
283
kfet/views.py
283
kfet/views.py
|
@ -18,7 +18,7 @@ from django.contrib.auth.models import User, Permission, Group
|
||||||
from django.http import HttpResponse, JsonResponse, Http404
|
from django.http import HttpResponse, JsonResponse, Http404
|
||||||
from django.forms import modelformset_factory, formset_factory
|
from django.forms import modelformset_factory, formset_factory
|
||||||
from django.db import IntegrityError, transaction
|
from django.db import IntegrityError, transaction
|
||||||
from django.db.models import F, Sum, Prefetch, Count, Func
|
from django.db.models import Q, F, Sum, Prefetch, Count, Func
|
||||||
from django.db.models.functions import Coalesce
|
from django.db.models.functions import Coalesce
|
||||||
from django.utils import timezone
|
from django.utils import timezone
|
||||||
from django.utils.crypto import get_random_string
|
from django.utils.crypto import get_random_string
|
||||||
|
@ -26,7 +26,7 @@ from gestioncof.models import CofProfile, Clipper
|
||||||
from kfet.decorators import teamkfet_required
|
from kfet.decorators import teamkfet_required
|
||||||
from kfet.models import (Account, Checkout, Article, Settings, AccountNegative,
|
from kfet.models import (Account, Checkout, Article, Settings, AccountNegative,
|
||||||
CheckoutStatement, GenericTeamToken, Supplier, SupplierArticle, Inventory,
|
CheckoutStatement, GenericTeamToken, Supplier, SupplierArticle, Inventory,
|
||||||
InventoryArticle, Order, OrderArticle)
|
InventoryArticle, Order, OrderArticle, TransferGroup, Transfer)
|
||||||
from kfet.forms import *
|
from kfet.forms import *
|
||||||
from collections import defaultdict
|
from collections import defaultdict
|
||||||
from kfet import consumers
|
from kfet import consumers
|
||||||
|
@ -1097,26 +1097,47 @@ def kpsul_perform_operations(request):
|
||||||
@teamkfet_required
|
@teamkfet_required
|
||||||
def kpsul_cancel_operations(request):
|
def kpsul_cancel_operations(request):
|
||||||
# Pour la réponse
|
# Pour la réponse
|
||||||
data = { 'canceled': [], 'warnings': {}, 'errors': {}}
|
data = {'canceled': {}, 'warnings': {}, 'errors': {}}
|
||||||
|
|
||||||
# Checking if BAD REQUEST (opes_pk not int or not existing)
|
# Checking if BAD REQUEST (opes_pk not int or not existing)
|
||||||
try:
|
try:
|
||||||
# Set pour virer les doublons
|
# Set pour virer les doublons
|
||||||
opes_post = set(map(int, filter(None, request.POST.getlist('operations[]', []))))
|
opes_post = set(map(lambda s: int(s.split()[1]),
|
||||||
|
filter(lambda s: s.split()[0] == 'ope',
|
||||||
|
request.POST.getlist('operations[]', []))))
|
||||||
|
transfers_post = \
|
||||||
|
set(map(lambda s: int(s.split()[1]),
|
||||||
|
filter(lambda s: s.split()[0] == 'transfer',
|
||||||
|
request.POST.getlist('operations[]', []))))
|
||||||
except ValueError:
|
except ValueError:
|
||||||
return JsonResponse(data, status=400)
|
return JsonResponse(data, status=400)
|
||||||
|
|
||||||
opes_all = (
|
opes_all = (
|
||||||
Operation.objects
|
Operation.objects
|
||||||
.select_related('group', 'group__on_acc', 'group__on_acc__negative')
|
.select_related('group', 'group__on_acc', 'group__on_acc__negative')
|
||||||
.filter(pk__in=opes_post))
|
.filter(pk__in=opes_post))
|
||||||
opes_pk = [ ope.pk for ope in opes_all ]
|
opes_pk = [ ope.pk for ope in opes_all ]
|
||||||
opes_notexisting = [ ope for ope in opes_post if ope not in opes_pk ]
|
opes_notexisting = [ ope for ope in opes_post if ope not in opes_pk ]
|
||||||
if opes_notexisting:
|
|
||||||
data['errors']['opes_notexisting'] = opes_notexisting
|
transfers_all = (
|
||||||
|
Transfer.objects
|
||||||
|
.select_related('group', 'from_acc', 'from_acc__negative',
|
||||||
|
'to_acc', 'to_acc__negative')
|
||||||
|
.filter(pk__in=transfers_post))
|
||||||
|
transfers_pk = [transfer.pk for transfer in transfers_all]
|
||||||
|
transfers_notexisting = [transfer for transfer in transfers_post
|
||||||
|
if transfer not in transfers_pk]
|
||||||
|
|
||||||
|
if transfers_notexisting or opes_notexisting:
|
||||||
|
if transfers_notexisting:
|
||||||
|
data['errors']['transfers_notexisting'] = transfers_notexisting
|
||||||
|
if opes_notexisting:
|
||||||
|
data['errors']['opes_notexisting'] = opes_notexisting
|
||||||
return JsonResponse(data, status=400)
|
return JsonResponse(data, status=400)
|
||||||
|
|
||||||
opes_already_canceled = [] # Déjà annulée
|
already_canceled = {} # Opération/Transfert déjà annulé
|
||||||
opes = [] # Pas déjà annulée
|
opes = [] # Pas déjà annulée
|
||||||
|
transfers = []
|
||||||
required_perms = set()
|
required_perms = set()
|
||||||
stop_all = False
|
stop_all = False
|
||||||
cancel_duration = Settings.CANCEL_DURATION()
|
cancel_duration = Settings.CANCEL_DURATION()
|
||||||
|
@ -1127,7 +1148,7 @@ def kpsul_cancel_operations(request):
|
||||||
for ope in opes_all:
|
for ope in opes_all:
|
||||||
if ope.canceled_at:
|
if ope.canceled_at:
|
||||||
# Opération déjà annulée, va pour un warning en Response
|
# Opération déjà annulée, va pour un warning en Response
|
||||||
opes_already_canceled.append(ope.pk)
|
already_canceled['opes'].append(ope.pk)
|
||||||
else:
|
else:
|
||||||
opes.append(ope.pk)
|
opes.append(ope.pk)
|
||||||
# Si opé il y a plus de CANCEL_DURATION, permission requise
|
# Si opé il y a plus de CANCEL_DURATION, permission requise
|
||||||
|
@ -1161,7 +1182,7 @@ def kpsul_cancel_operations(request):
|
||||||
if not last_statement or last_statement.at < ope.group.at:
|
if not last_statement or last_statement.at < ope.group.at:
|
||||||
if ope.type == Operation.PURCHASE:
|
if ope.type == Operation.PURCHASE:
|
||||||
if ope.group.on_acc.is_cash:
|
if ope.group.on_acc.is_cash:
|
||||||
to_checkouts_balances[ope.group.checkout] -= - ope.amount
|
to_checkouts_balances[ope.group.checkout] -= -ope.amount
|
||||||
else:
|
else:
|
||||||
to_checkouts_balances[ope.group.checkout] -= ope.amount
|
to_checkouts_balances[ope.group.checkout] -= ope.amount
|
||||||
|
|
||||||
|
@ -1174,22 +1195,38 @@ def kpsul_cancel_operations(request):
|
||||||
# est recalculé automatiquement
|
# est recalculé automatiquement
|
||||||
if ope.article and ope.article_nb:
|
if ope.article and ope.article_nb:
|
||||||
last_stock = (InventoryArticle.objects
|
last_stock = (InventoryArticle.objects
|
||||||
.select_related('inventory')
|
.select_related('inventory')
|
||||||
.filter(article=ope.article)
|
.filter(article=ope.article)
|
||||||
.order_by('inventory__at')
|
.order_by('inventory__at')
|
||||||
.last())
|
.last())
|
||||||
if not last_stock or last_stock.inventory.at < ope.group.at:
|
if not last_stock or last_stock.inventory.at < ope.group.at:
|
||||||
to_articles_stocks[ope.article] += ope.article_nb
|
to_articles_stocks[ope.article] += ope.article_nb
|
||||||
|
|
||||||
if not opes:
|
for transfer in transfers_all:
|
||||||
data['warnings']['already_canceled'] = opes_already_canceled
|
if transfer.canceled_at:
|
||||||
|
# Transfert déjà annulé, va pour un warning en Response
|
||||||
|
already_canceled['transfers'].append(transfer.pk)
|
||||||
|
else:
|
||||||
|
transfers.append(transfer.pk)
|
||||||
|
# Si transfer il y a plus de CANCEL_DURATION, permission requise
|
||||||
|
if transfer.group.at + cancel_duration < timezone.now():
|
||||||
|
required_perms.add('kfet.cancel_old_operations')
|
||||||
|
|
||||||
|
# Calcul de toutes modifs à faire en cas de validation
|
||||||
|
|
||||||
|
# Pour les balances de comptes
|
||||||
|
to_accounts_balances[transfer.from_acc] += transfer.amount
|
||||||
|
to_accounts_balances[transfer.to_acc] += -transfer.amount
|
||||||
|
|
||||||
|
if not opes and not transfers:
|
||||||
|
data['warnings']['already_canceled'] = already_canceled
|
||||||
return JsonResponse(data)
|
return JsonResponse(data)
|
||||||
|
|
||||||
negative_accounts = []
|
negative_accounts = []
|
||||||
# Checking permissions or stop
|
# Checking permissions or stop
|
||||||
for account in to_accounts_balances:
|
for account in to_accounts_balances:
|
||||||
(perms, stop) = account.perms_to_perform_operation(
|
(perms, stop) = account.perms_to_perform_operation(
|
||||||
amount = to_accounts_balances[account])
|
amount=to_accounts_balances[account])
|
||||||
required_perms |= perms
|
required_perms |= perms
|
||||||
stop_all = stop_all or stop
|
stop_all = stop_all or stop
|
||||||
if stop:
|
if stop:
|
||||||
|
@ -1209,25 +1246,31 @@ def kpsul_cancel_operations(request):
|
||||||
with transaction.atomic():
|
with transaction.atomic():
|
||||||
(Operation.objects.filter(pk__in=opes)
|
(Operation.objects.filter(pk__in=opes)
|
||||||
.update(canceled_by=canceled_by, canceled_at=canceled_at))
|
.update(canceled_by=canceled_by, canceled_at=canceled_at))
|
||||||
|
|
||||||
|
(Transfer.objects.filter(pk__in=transfers)
|
||||||
|
.update(canceled_by=canceled_by, canceled_at=canceled_at))
|
||||||
|
|
||||||
for account in to_accounts_balances:
|
for account in to_accounts_balances:
|
||||||
Account.objects.filter(pk=account.pk).update(
|
Account.objects.filter(pk=account.pk).update(
|
||||||
balance = F('balance') + to_accounts_balances[account])
|
balance=F('balance') + to_accounts_balances[account])
|
||||||
for checkout in to_checkouts_balances:
|
for checkout in to_checkouts_balances:
|
||||||
Checkout.objects.filter(pk=checkout.pk).update(
|
Checkout.objects.filter(pk=checkout.pk).update(
|
||||||
balance = F('balance') + to_checkouts_balances[checkout])
|
balance=F('balance') + to_checkouts_balances[checkout])
|
||||||
for group in to_groups_amounts:
|
for group in to_groups_amounts:
|
||||||
OperationGroup.objects.filter(pk=group.pk).update(
|
OperationGroup.objects.filter(pk=group.pk).update(
|
||||||
amount = F('amount') + to_groups_amounts[group])
|
amount=F('amount') + to_groups_amounts[group])
|
||||||
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 = { 'opegroups': [], 'opes': [], 'checkouts': [], 'articles': [] }
|
websocket_data = {'opegroups': [], 'opes': [],
|
||||||
|
'checkouts': [], 'articles': []}
|
||||||
# Need refresh from db cause we used update on querysets
|
# Need refresh from db cause we used update on querysets
|
||||||
opegroups_pk = [ opegroup.pk for opegroup in to_groups_amounts ]
|
opegroups_pk = [opegroup.pk for opegroup in to_groups_amounts]
|
||||||
opegroups = (OperationGroup.objects
|
opegroups = (OperationGroup.objects
|
||||||
.values('id','amount','is_cof').filter(pk__in=opegroups_pk))
|
.values('id', 'amount', 'is_cof')
|
||||||
|
.filter(pk__in=opegroups_pk))
|
||||||
for opegroup in opegroups:
|
for opegroup in opegroups:
|
||||||
websocket_data['opegroups'].append({
|
websocket_data['opegroups'].append({
|
||||||
'cancellation': True,
|
'cancellation': True,
|
||||||
|
@ -1244,15 +1287,16 @@ def kpsul_cancel_operations(request):
|
||||||
'canceled_at': canceled_at,
|
'canceled_at': canceled_at,
|
||||||
})
|
})
|
||||||
# Need refresh from db cause we used update on querysets
|
# Need refresh from db cause we used update on querysets
|
||||||
checkouts_pk = [ checkout.pk for checkout in to_checkouts_balances]
|
checkouts_pk = [checkout.pk for checkout in to_checkouts_balances]
|
||||||
checkouts = (Checkout.objects
|
checkouts = (Checkout.objects
|
||||||
.values('id', 'balance').filter(pk__in=checkouts_pk))
|
.values('id', 'balance')
|
||||||
|
.filter(pk__in=checkouts_pk))
|
||||||
for checkout in checkouts:
|
for checkout in checkouts:
|
||||||
websocket_data['checkouts'].append({
|
websocket_data['checkouts'].append({
|
||||||
'id': checkout['id'],
|
'id': checkout['id'],
|
||||||
'balance': checkout['balance']})
|
'balance': checkout['balance']})
|
||||||
# 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 articles in to_articles_stocks]
|
articles_pk = [article.pk for articles 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({
|
||||||
|
@ -1260,9 +1304,10 @@ def kpsul_cancel_operations(request):
|
||||||
'stock': article['stock']})
|
'stock': article['stock']})
|
||||||
consumers.KPsul.group_send('kfet.kpsul', websocket_data)
|
consumers.KPsul.group_send('kfet.kpsul', websocket_data)
|
||||||
|
|
||||||
data['canceled'] = opes
|
data['canceled']['opes'] = opes
|
||||||
if opes_already_canceled:
|
data['canceled']['transfers'] = transfers
|
||||||
data['warnings']['already_canceled'] = opes_already_canceled
|
if already_canceled:
|
||||||
|
data['warnings']['already_canceled'] = already_canceled
|
||||||
return JsonResponse(data)
|
return JsonResponse(data)
|
||||||
|
|
||||||
@login_required
|
@login_required
|
||||||
|
@ -1270,45 +1315,77 @@ def history_json(request):
|
||||||
# Récupération des paramètres
|
# Récupération des paramètres
|
||||||
from_date = request.POST.get('from', None)
|
from_date = request.POST.get('from', None)
|
||||||
to_date = request.POST.get('to', None)
|
to_date = request.POST.get('to', None)
|
||||||
limit = request.POST.get('limit', None);
|
|
||||||
checkouts = request.POST.getlist('checkouts[]', None)
|
checkouts = request.POST.getlist('checkouts[]', None)
|
||||||
accounts = request.POST.getlist('accounts[]', None)
|
accounts = request.POST.getlist('accounts[]', None)
|
||||||
|
transfers_only = request.POST.get('transfersonly', None)
|
||||||
|
|
||||||
# Construction de la requête (sur les opérations) pour le prefetch
|
# Construction de la requête (sur les opérations) pour le prefetch
|
||||||
queryset_prefetch = Operation.objects.select_related(
|
ope_queryset_prefetch = Operation.objects.select_related(
|
||||||
'canceled_by__trigramme', 'addcost_for__trigramme',
|
'canceled_by__trigramme', 'addcost_for__trigramme',
|
||||||
'article__name')
|
'article__name')
|
||||||
|
ope_prefetch = Prefetch('opes',
|
||||||
|
queryset = ope_queryset_prefetch)
|
||||||
|
|
||||||
|
transfer_queryset_prefetch = Transfer.objects.select_related(
|
||||||
|
'from_acc__trigramme', 'to_acc__trigramme',
|
||||||
|
'from_acc__id', 'to_acc__id',
|
||||||
|
'canceled_by__trigramme')
|
||||||
|
|
||||||
|
if accounts:
|
||||||
|
transfer_queryset_prefetch = transfer_queryset_prefetch.filter(
|
||||||
|
Q(from_acc__id__in=accounts) |
|
||||||
|
Q(to_acc__id__in=accounts))
|
||||||
|
|
||||||
|
if not request.user.has_perm('kfet.is_team'):
|
||||||
|
acc = request.user.profile.account_kfet
|
||||||
|
transfer_queryset_prefetch = transfer_queryset_prefetch.filter(
|
||||||
|
Q(from_acc=acc) | Q(to_acc=acc))
|
||||||
|
|
||||||
|
transfer_prefetch = Prefetch('transfers',
|
||||||
|
queryset=transfer_queryset_prefetch,
|
||||||
|
to_attr='filtered_transfers')
|
||||||
|
|
||||||
|
|
||||||
# Construction de la requête principale
|
# Construction de la requête principale
|
||||||
opegroups = (OperationGroup.objects
|
opegroups = (OperationGroup.objects
|
||||||
.prefetch_related(Prefetch('opes', queryset = queryset_prefetch))
|
.prefetch_related(ope_prefetch)
|
||||||
.select_related('on_acc__trigramme', 'valid_by__trigramme')
|
.select_related('on_acc__trigramme', 'valid_by__trigramme')
|
||||||
.order_by('at')
|
.order_by('at')
|
||||||
)
|
)
|
||||||
|
|
||||||
|
transfergroups = (
|
||||||
|
TransferGroup.objects
|
||||||
|
.prefetch_related(transfer_prefetch)
|
||||||
|
.select_related('valid_by__trigramme')
|
||||||
|
.order_by('at'))
|
||||||
|
|
||||||
# Application des filtres
|
# Application des filtres
|
||||||
if from_date:
|
if from_date:
|
||||||
opegroups = opegroups.filter(at__gte=from_date)
|
opegroups = opegroups.filter(at__gte=from_date)
|
||||||
|
transfergroups = transfergroups.filter(at__gte=from_date)
|
||||||
if to_date:
|
if to_date:
|
||||||
opegroups = opegroups.filter(at__lt=to_date)
|
opegroups = opegroups.filter(at__lt=to_date)
|
||||||
|
transfergroups = transfergroups.filter(at__lt=to_date)
|
||||||
if checkouts:
|
if checkouts:
|
||||||
opegroups = opegroups.filter(checkout_id__in=checkouts)
|
opegroups = opegroups.filter(checkout_id__in=checkouts)
|
||||||
|
transfergroups = TransferGroup.objects.none()
|
||||||
|
if transfers_only:
|
||||||
|
opegroups = OperationGroup.objects.none()
|
||||||
if accounts:
|
if accounts:
|
||||||
opegroups = opegroups.filter(on_acc_id__in=accounts)
|
opegroups = opegroups.filter(on_acc_id__in=accounts)
|
||||||
# Un non-membre de l'équipe n'a que accès à son historique
|
# Un non-membre de l'équipe n'a que accès à son historique
|
||||||
if not request.user.has_perm('kfet.is_team'):
|
if not request.user.has_perm('kfet.is_team'):
|
||||||
opegroups = opegroups.filter(on_acc=request.user.profile.account_kfet)
|
opegroups = opegroups.filter(on_acc=request.user.profile.account_kfet)
|
||||||
if limit:
|
|
||||||
opegroups = opegroups[:limit]
|
|
||||||
|
|
||||||
|
|
||||||
# Construction de la réponse
|
# Construction de la réponse
|
||||||
opegroups_list = []
|
opegroups_list = []
|
||||||
for opegroup in opegroups:
|
for opegroup in opegroups:
|
||||||
opegroup_dict = {
|
opegroup_dict = {
|
||||||
|
'type' : 'opegroup',
|
||||||
'id' : opegroup.id,
|
'id' : opegroup.id,
|
||||||
'amount' : opegroup.amount,
|
'amount' : opegroup.amount,
|
||||||
'at' : opegroup.at,
|
'at' : opegroup.at,
|
||||||
'checkout_id': opegroup.checkout_id,
|
|
||||||
'is_cof' : opegroup.is_cof,
|
'is_cof' : opegroup.is_cof,
|
||||||
'comment' : opegroup.comment,
|
'comment' : opegroup.comment,
|
||||||
'opes' : [],
|
'opes' : [],
|
||||||
|
@ -1337,7 +1414,41 @@ def history_json(request):
|
||||||
ope.canceled_by and ope.canceled_by.trigramme or None)
|
ope.canceled_by and ope.canceled_by.trigramme or None)
|
||||||
opegroup_dict['opes'].append(ope_dict)
|
opegroup_dict['opes'].append(ope_dict)
|
||||||
opegroups_list.append(opegroup_dict)
|
opegroups_list.append(opegroup_dict)
|
||||||
return JsonResponse({ 'opegroups': opegroups_list })
|
|
||||||
|
for transfergroup in transfergroups:
|
||||||
|
if transfergroup.filtered_transfers:
|
||||||
|
transfergroup_dict = {
|
||||||
|
'type': 'transfergroup',
|
||||||
|
'id': transfergroup.id,
|
||||||
|
'at': transfergroup.at,
|
||||||
|
'comment': transfergroup.comment,
|
||||||
|
'opes': [],
|
||||||
|
}
|
||||||
|
if request.user.has_perm('kfet.is_team'):
|
||||||
|
transfergroup_dict['valid_by__trigramme'] = (
|
||||||
|
transfergroup.valid_by
|
||||||
|
and transfergroup.valid_by.trigramme
|
||||||
|
or None)
|
||||||
|
|
||||||
|
for transfer in transfergroup.filtered_transfers:
|
||||||
|
transfer_dict = {
|
||||||
|
'id': transfer.id,
|
||||||
|
'amount': transfer.amount,
|
||||||
|
'canceled_at': transfer.canceled_at,
|
||||||
|
'from_acc': transfer.from_acc.trigramme,
|
||||||
|
'to_acc': transfer.to_acc.trigramme,
|
||||||
|
}
|
||||||
|
if request.user.has_perm('kfet.is_team'):
|
||||||
|
transfer_dict['canceled_by__trigramme'] = (
|
||||||
|
transfer.canceled_by
|
||||||
|
and transfer.canceled_by.trigramme
|
||||||
|
or None)
|
||||||
|
transfergroup_dict['opes'].append(transfer_dict)
|
||||||
|
opegroups_list.append(transfergroup_dict)
|
||||||
|
|
||||||
|
opegroups_list.sort(key=lambda group: group['at'])
|
||||||
|
|
||||||
|
return JsonResponse({'opegroups': opegroups_list})
|
||||||
|
|
||||||
@teamkfet_required
|
@teamkfet_required
|
||||||
def kpsul_articles_data(request):
|
def kpsul_articles_data(request):
|
||||||
|
@ -1483,104 +1594,6 @@ def perform_transfers(request):
|
||||||
|
|
||||||
return JsonResponse(data)
|
return JsonResponse(data)
|
||||||
|
|
||||||
@teamkfet_required
|
|
||||||
def cancel_transfers(request):
|
|
||||||
# Pour la réponse
|
|
||||||
data = { 'canceled': [], 'warnings': {}, 'errors': {}}
|
|
||||||
|
|
||||||
# Checking if BAD REQUEST (transfers_pk not int or not existing)
|
|
||||||
try:
|
|
||||||
# Set pour virer les doublons
|
|
||||||
transfers_post = set(map(int, filter(None, request.POST.getlist('transfers[]', []))))
|
|
||||||
except ValueError:
|
|
||||||
return JsonResponse(data, status=400)
|
|
||||||
transfers_all = (
|
|
||||||
Transfer.objects
|
|
||||||
.select_related('group', 'from_acc', 'from_acc__negative',
|
|
||||||
'to_acc', 'to_acc__negative')
|
|
||||||
.filter(pk__in=transfers_post))
|
|
||||||
transfers_pk = [ transfer.pk for transfer in transfers_all ]
|
|
||||||
transfers_notexisting = [ transfer for transfer in transfers_post
|
|
||||||
if transfer not in transfers_pk ]
|
|
||||||
if transfers_notexisting:
|
|
||||||
data['errors']['transfers_notexisting'] = transfers_notexisting
|
|
||||||
return JsonResponse(data, status=400)
|
|
||||||
|
|
||||||
transfers_already_canceled = [] # Déjà annulée
|
|
||||||
transfers = [] # Pas déjà annulée
|
|
||||||
required_perms = set()
|
|
||||||
stop_all = False
|
|
||||||
cancel_duration = Settings.CANCEL_DURATION()
|
|
||||||
to_accounts_balances = defaultdict(lambda:0) # Modifs à faire sur les balances des comptes
|
|
||||||
for transfer in transfers_all:
|
|
||||||
if transfer.canceled_at:
|
|
||||||
# Transfert déjà annulé, va pour un warning en Response
|
|
||||||
transfers_already_canceled.append(transfer.pk)
|
|
||||||
else:
|
|
||||||
transfers.append(transfer.pk)
|
|
||||||
# Si transfer il y a plus de CANCEL_DURATION, permission requise
|
|
||||||
if transfer.group.at + cancel_duration < timezone.now():
|
|
||||||
required_perms.add('kfet.cancel_old_operations')
|
|
||||||
|
|
||||||
# Calcul de toutes modifs à faire en cas de validation
|
|
||||||
|
|
||||||
# Pour les balances de comptes
|
|
||||||
to_accounts_balances[transfer.from_acc] += transfer.amount
|
|
||||||
to_accounts_balances[transfer.to_acc] += -transfer.amount
|
|
||||||
|
|
||||||
if not transfers:
|
|
||||||
data['warnings']['already_canceled'] = transfers_already_canceled
|
|
||||||
return JsonResponse(data)
|
|
||||||
|
|
||||||
negative_accounts = []
|
|
||||||
# Checking permissions or stop
|
|
||||||
for account in to_accounts_balances:
|
|
||||||
(perms, stop) = account.perms_to_perform_operation(
|
|
||||||
amount = to_accounts_balances[account])
|
|
||||||
required_perms |= perms
|
|
||||||
stop_all = stop_all or stop
|
|
||||||
if stop:
|
|
||||||
negative_accounts.append(account.trigramme)
|
|
||||||
|
|
||||||
print(required_perms)
|
|
||||||
print(request.user.get_all_permissions())
|
|
||||||
|
|
||||||
if stop_all or not request.user.has_perms(required_perms):
|
|
||||||
missing_perms = get_missing_perms(required_perms, request.user)
|
|
||||||
if missing_perms:
|
|
||||||
data['errors']['missing_perms'] = missing_perms
|
|
||||||
if stop_all:
|
|
||||||
data['errors']['negative'] = negative_accounts
|
|
||||||
return JsonResponse(data, status=403)
|
|
||||||
|
|
||||||
canceled_by = required_perms and request.user.profile.account_kfet or None
|
|
||||||
canceled_at = timezone.now()
|
|
||||||
|
|
||||||
with transaction.atomic():
|
|
||||||
(Transfer.objects.filter(pk__in=transfers)
|
|
||||||
.update(canceled_by=canceled_by, canceled_at=canceled_at))
|
|
||||||
|
|
||||||
for account in to_accounts_balances:
|
|
||||||
Account.objects.filter(pk=account.pk).update(
|
|
||||||
balance = F('balance') + to_accounts_balances[account])
|
|
||||||
account.refresh_from_db()
|
|
||||||
if account.balance < 0:
|
|
||||||
if hasattr(account, 'negative'):
|
|
||||||
if not account.negative.start:
|
|
||||||
account.negative.start = timezone.now()
|
|
||||||
account.negative.save()
|
|
||||||
else:
|
|
||||||
negative = AccountNegative(
|
|
||||||
account = account, start = timezone.now())
|
|
||||||
negative.save()
|
|
||||||
elif (hasattr(account, 'negative')
|
|
||||||
and not account.negative.balance_offset):
|
|
||||||
account.negative.delete()
|
|
||||||
|
|
||||||
data['canceled'] = transfers
|
|
||||||
if transfers_already_canceled:
|
|
||||||
data['warnings']['already_canceled'] = transfers_already_canceled
|
|
||||||
return JsonResponse(data)
|
|
||||||
|
|
||||||
class InventoryList(ListView):
|
class InventoryList(ListView):
|
||||||
queryset = (Inventory.objects
|
queryset = (Inventory.objects
|
||||||
|
|
Loading…
Reference in a new issue