forked from DGNum/gestioCOF
Merge branch 'Aufinal/transferts_historique' into 'master'
Rajoute les transferts dans l'historique Closes #77 and #233 See merge request klub-dev-ens/gestioCOF!399
This commit is contained in:
commit
922190d20f
9 changed files with 530 additions and 571 deletions
|
@ -20,7 +20,7 @@
|
|||
z-index:10;
|
||||
}
|
||||
|
||||
#history .opegroup {
|
||||
#history .group {
|
||||
height:30px;
|
||||
line-height:30px;
|
||||
background-color: #c63b52;
|
||||
|
@ -30,29 +30,29 @@
|
|||
overflow:auto;
|
||||
}
|
||||
|
||||
#history .opegroup .time {
|
||||
#history .group .time {
|
||||
width:70px;
|
||||
}
|
||||
|
||||
#history .opegroup .trigramme {
|
||||
#history .group .trigramme {
|
||||
width:55px;
|
||||
text-align:right;
|
||||
}
|
||||
|
||||
#history .opegroup .amount {
|
||||
#history .group .amount {
|
||||
text-align:right;
|
||||
width:90px;
|
||||
}
|
||||
|
||||
#history .opegroup .valid_by {
|
||||
#history .group .valid_by {
|
||||
padding-left:20px
|
||||
}
|
||||
|
||||
#history .opegroup .comment {
|
||||
#history .group .comment {
|
||||
padding-left:20px;
|
||||
}
|
||||
|
||||
#history .ope {
|
||||
#history .entry {
|
||||
position:relative;
|
||||
height:25px;
|
||||
line-height:24px;
|
||||
|
@ -61,38 +61,38 @@
|
|||
overflow:auto;
|
||||
}
|
||||
|
||||
#history .ope .amount {
|
||||
#history .entry .amount {
|
||||
width:50px;
|
||||
text-align:right;
|
||||
}
|
||||
|
||||
#history .ope .infos1 {
|
||||
#history .entry .infos1 {
|
||||
width:80px;
|
||||
text-align:right;
|
||||
}
|
||||
|
||||
#history .ope .infos2 {
|
||||
#history .entry .infos2 {
|
||||
padding-left:15px;
|
||||
}
|
||||
|
||||
#history .ope .addcost {
|
||||
#history .entry .addcost {
|
||||
padding-left:20px;
|
||||
}
|
||||
|
||||
#history .ope .canceled {
|
||||
#history .entry .canceled {
|
||||
padding-left:20px;
|
||||
}
|
||||
|
||||
#history div.ope.ui-selected, #history div.ope.ui-selecting {
|
||||
#history div.entry.ui-selected, #history div.entry.ui-selecting {
|
||||
background-color:rgba(200,16,46,0.6);
|
||||
color:#FFF;
|
||||
}
|
||||
|
||||
#history .ope.canceled, #history .transfer.canceled {
|
||||
#history .entry.canceled {
|
||||
color:#444;
|
||||
}
|
||||
|
||||
#history .ope.canceled::before, #history.transfer.canceled::before {
|
||||
#history .entry.canceled::before {
|
||||
position: absolute;
|
||||
content: ' ';
|
||||
width:100%;
|
||||
|
@ -101,10 +101,11 @@
|
|||
border-top: 1px solid rgba(200,16,46,0.5);
|
||||
}
|
||||
|
||||
#history .transfer .amount {
|
||||
width:80px;
|
||||
#history .group .infos {
|
||||
text-align:center;
|
||||
width:145px;
|
||||
}
|
||||
|
||||
#history .transfer .from_acc {
|
||||
padding-left:10px;
|
||||
#history .entry .glyphicon {
|
||||
padding-left:15px;
|
||||
}
|
||||
|
|
|
@ -2,31 +2,59 @@ function dateUTCToParis(date) {
|
|||
return moment.tz(date, 'UTC').tz('Europe/Paris');
|
||||
}
|
||||
|
||||
// TODO : classifier (later)
|
||||
function KHistory(options = {}) {
|
||||
$.extend(this, KHistory.default_options, options);
|
||||
|
||||
this.$container = $(this.container);
|
||||
|
||||
this.$container.selectable({
|
||||
filter: 'div.group, div.entry',
|
||||
selected: function (e, ui) {
|
||||
$(ui.selected).each(function () {
|
||||
if ($(this).hasClass('group')) {
|
||||
var id = $(this).data('id');
|
||||
$(this).siblings('.entry').filter(function () {
|
||||
return $(this).data('group_id') == id
|
||||
}).addClass('ui-selected');
|
||||
}
|
||||
});
|
||||
},
|
||||
});
|
||||
|
||||
this.reset = function () {
|
||||
this.$container.html('');
|
||||
};
|
||||
|
||||
this.addOpeGroup = function (opegroup) {
|
||||
var $day = this._getOrCreateDay(opegroup['at']);
|
||||
var $opegroup = this._opeGroupHtml(opegroup);
|
||||
this.add_history_group = function (group) {
|
||||
var $day = this._get_or_create_day(group['at']);
|
||||
var $group = this._group_html(group);
|
||||
|
||||
$day.after($opegroup);
|
||||
$day.after($group);
|
||||
|
||||
var trigramme = opegroup['on_acc_trigramme'];
|
||||
var is_cof = opegroup['is_cof'];
|
||||
for (var i = 0; i < opegroup['opes'].length; i++) {
|
||||
var $ope = this._opeHtml(opegroup['opes'][i], is_cof, trigramme);
|
||||
$ope.data('opegroup', opegroup['id']);
|
||||
$opegroup.after($ope);
|
||||
var trigramme = group['on_acc_trigramme'];
|
||||
var is_cof = group['is_cof'];
|
||||
var type = group['type']
|
||||
// TODO : simplifier ça ?
|
||||
switch (type) {
|
||||
case 'operation':
|
||||
for (let ope of group['entries']) {
|
||||
var $ope = this._ope_html(ope, is_cof, trigramme);
|
||||
$ope.data('group_id', group['id']);
|
||||
$group.after($ope);
|
||||
}
|
||||
break;
|
||||
case 'transfer':
|
||||
for (let transfer of group['entries']) {
|
||||
var $transfer = this._transfer_html(transfer);
|
||||
$transfer.data('group_id', group['id']);
|
||||
$group.after($transfer);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
this._opeHtml = function (ope, is_cof, trigramme) {
|
||||
this._ope_html = function (ope, is_cof, trigramme) {
|
||||
var $ope_html = $(this.template_ope);
|
||||
var parsed_amount = parseFloat(ope['amount']);
|
||||
var amount = amountDisplay(parsed_amount, is_cof, trigramme);
|
||||
|
@ -54,7 +82,8 @@ function KHistory(options = {}) {
|
|||
}
|
||||
|
||||
$ope_html
|
||||
.data('ope', ope['id'])
|
||||
.data('type', 'operation')
|
||||
.data('id', ope['id'])
|
||||
.find('.amount').text(amount).end()
|
||||
.find('.infos1').text(infos1).end()
|
||||
.find('.infos2').text(infos2).end();
|
||||
|
@ -66,50 +95,85 @@ function KHistory(options = {}) {
|
|||
}
|
||||
|
||||
if (ope['canceled_at'])
|
||||
this.cancelOpe(ope, $ope_html);
|
||||
this.cancel_entry(ope, $ope_html);
|
||||
|
||||
return $ope_html;
|
||||
}
|
||||
|
||||
this.cancelOpe = function (ope, $ope = null) {
|
||||
if (!$ope)
|
||||
$ope = this.findOpe(ope['id']);
|
||||
this._transfer_html = function (transfer) {
|
||||
var $transfer_html = $(this.template_transfer);
|
||||
var parsed_amount = parseFloat(transfer['amount']);
|
||||
var amount = parsed_amount.toFixed(2) + '€';
|
||||
|
||||
var cancel = 'Annulé';
|
||||
var canceled_at = dateUTCToParis(ope['canceled_at']);
|
||||
if (ope['canceled_by__trigramme'])
|
||||
cancel += ' par ' + ope['canceled_by__trigramme'];
|
||||
cancel += ' le ' + canceled_at.format('DD/MM/YY à HH:mm:ss');
|
||||
$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();
|
||||
|
||||
$ope.addClass('canceled').find('.canceled').text(cancel);
|
||||
if (transfer['canceled_at'])
|
||||
this.cancel_entry(transfer, $transfer_html);
|
||||
|
||||
return $transfer_html;
|
||||
}
|
||||
|
||||
this._opeGroupHtml = function (opegroup) {
|
||||
var $opegroup_html = $(this.template_opegroup);
|
||||
|
||||
var at = dateUTCToParis(opegroup['at']).format('HH:mm:ss');
|
||||
var trigramme = opegroup['on_acc__trigramme'];
|
||||
this.cancel_entry = function (entry, $entry = null) {
|
||||
if (!$entry)
|
||||
$entry = this.find_entry(entry["id"], entry["type"]);
|
||||
|
||||
var cancel = 'Annulé';
|
||||
var canceled_at = dateUTCToParis(entry['canceled_at']);
|
||||
if (entry['canceled_by__trigramme'])
|
||||
cancel += ' par ' + entry['canceled_by__trigramme'];
|
||||
cancel += ' le ' + canceled_at.format('DD/MM/YY à HH:mm:ss');
|
||||
|
||||
$entry.addClass('canceled').find('.canceled').text(cancel);
|
||||
}
|
||||
|
||||
this._group_html = function (group) {
|
||||
var type = group['type'];
|
||||
|
||||
|
||||
switch (type) {
|
||||
case 'operation':
|
||||
var $group_html = $(this.template_opegroup);
|
||||
var trigramme = group['on_acc__trigramme'];
|
||||
var amount = amountDisplay(
|
||||
parseFloat(opegroup['amount']), opegroup['is_cof'], trigramme);
|
||||
var comment = opegroup['comment'] || '';
|
||||
parseFloat(group['amount']), group['is_cof'], trigramme);
|
||||
break;
|
||||
case 'transfer':
|
||||
var $group_html = $(this.template_transfergroup);
|
||||
$group_html.find('.infos').text('Transferts').end()
|
||||
var trigramme = '';
|
||||
var amount = '';
|
||||
break;
|
||||
}
|
||||
|
||||
$opegroup_html
|
||||
.data('opegroup', opegroup['id'])
|
||||
|
||||
var at = dateUTCToParis(group['at']).format('HH:mm:ss');
|
||||
var comment = group['comment'] || '';
|
||||
|
||||
$group_html
|
||||
.data('type', type)
|
||||
.data('id', group['id'])
|
||||
.find('.time').text(at).end()
|
||||
.find('.amount').text(amount).end()
|
||||
.find('.comment').text(comment).end()
|
||||
.find('.trigramme').text(trigramme).end();
|
||||
|
||||
if (!this.display_trigramme)
|
||||
$opegroup_html.find('.trigramme').remove();
|
||||
$group_html.find('.trigramme').remove();
|
||||
$group_html.find('.info').remove();
|
||||
|
||||
if (opegroup['valid_by__trigramme'])
|
||||
$opegroup_html.find('.valid_by').text('Par ' + opegroup['valid_by__trigramme']);
|
||||
if (group['valid_by__trigramme'])
|
||||
$group_html.find('.valid_by').text('Par ' + group['valid_by__trigramme']);
|
||||
|
||||
return $opegroup_html;
|
||||
return $group_html;
|
||||
}
|
||||
|
||||
this._getOrCreateDay = function (date) {
|
||||
this._get_or_create_day = function (date) {
|
||||
var at = dateUTCToParis(date);
|
||||
var at_ser = at.format('YYYY-MM-DD');
|
||||
var $day = this.$container.find('.day').filter(function () {
|
||||
|
@ -118,35 +182,123 @@ function KHistory(options = {}) {
|
|||
if ($day.length == 1)
|
||||
return $day;
|
||||
var $day = $(this.template_day).prependTo(this.$container);
|
||||
return $day.data('date', at_ser).text(at.format('D MMMM'));
|
||||
return $day.data('date', at_ser).text(at.format('D MMMM YYYY'));
|
||||
}
|
||||
|
||||
this.findOpeGroup = function (id) {
|
||||
return this.$container.find('.opegroup').filter(function () {
|
||||
return $(this).data('opegroup') == id
|
||||
this.find_group = function (id, type = "operation") {
|
||||
return this.$container.find('.group').filter(function () {
|
||||
return ($(this).data('id') == id && $(this).data("type") == type)
|
||||
});
|
||||
}
|
||||
|
||||
this.findOpe = function (id) {
|
||||
return this.$container.find('.ope').filter(function () {
|
||||
return $(this).data('ope') == id
|
||||
this.find_entry = function (id, type = 'operation') {
|
||||
return this.$container.find('.entry').filter(function () {
|
||||
return ($(this).data('id') == id && $(this).data('type') == type)
|
||||
});
|
||||
}
|
||||
|
||||
this.cancelOpeGroup = function (opegroup) {
|
||||
var $opegroup = this.findOpeGroup(opegroup['id']);
|
||||
var trigramme = $opegroup.find('.trigramme').text();
|
||||
this.update_opegroup = function (group, type = "operation") {
|
||||
var $group = this.find_group(group['id'], type);
|
||||
var trigramme = $group.find('.trigramme').text();
|
||||
var amount = amountDisplay(
|
||||
parseFloat(opegroup['amount']), opegroup['is_cof'], trigramme);
|
||||
$opegroup.find('.amount').text(amount);
|
||||
parseFloat(group['amount']), group['is_cof'], trigramme);
|
||||
$group.find('.amount').text(amount);
|
||||
}
|
||||
|
||||
this.fetch = function (fetch_options) {
|
||||
options = $.extend({}, this.fetch_options, fetch_options);
|
||||
var that = this;
|
||||
return $.ajax({
|
||||
dataType: "json",
|
||||
url: django_urls["kfet.history.json"](),
|
||||
method: "POST",
|
||||
data: options,
|
||||
}).done(function (data) {
|
||||
for (let group of data['groups']) {
|
||||
that.add_history_group(group);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
this._cancel = function (type, opes, password = "") {
|
||||
if (window.lock == 1)
|
||||
return false
|
||||
window.lock = 1;
|
||||
var that = this;
|
||||
return $.ajax({
|
||||
dataType: "json",
|
||||
url: django_urls[`kfet.${type}s.cancel`](),
|
||||
method: "POST",
|
||||
data: opes,
|
||||
beforeSend: function ($xhr) {
|
||||
$xhr.setRequestHeader("X-CSRFToken", csrftoken);
|
||||
if (password != '')
|
||||
$xhr.setRequestHeader("KFetPassword", password);
|
||||
},
|
||||
|
||||
}).done(function (data) {
|
||||
window.lock = 0;
|
||||
that.$container.find('.ui-selected').removeClass('ui-selected');
|
||||
for (let entry of data["canceled"]) {
|
||||
entry["type"] = type;
|
||||
that.cancel_entry(entry);
|
||||
}
|
||||
if (type == "operation") {
|
||||
for (let opegroup of data["opegroups_to_update"]) {
|
||||
that.update_opegroup(opegroup)
|
||||
}
|
||||
}
|
||||
}).fail(function ($xhr) {
|
||||
var data = $xhr.responseJSON;
|
||||
switch ($xhr.status) {
|
||||
case 403:
|
||||
requestAuth(data, function (password) {
|
||||
this.cancel(opes, password);
|
||||
});
|
||||
break;
|
||||
case 400:
|
||||
displayErrors(getErrorsHtml(data));
|
||||
break;
|
||||
}
|
||||
window.lock = 0;
|
||||
});
|
||||
}
|
||||
|
||||
this.cancel_selected = function () {
|
||||
var opes_to_cancel = {
|
||||
"transfers": [],
|
||||
"operations": [],
|
||||
}
|
||||
this.$container.find('.entry.ui-selected').each(function () {
|
||||
type = $(this).data("type");
|
||||
opes_to_cancel[`${type}s`].push($(this).data("id"));
|
||||
});
|
||||
if (opes_to_cancel["transfers"].length > 0 && opes_to_cancel["operations"].length > 0) {
|
||||
// Lancer 2 requêtes AJAX et gérer tous les cas d'erreurs possibles est trop complexe
|
||||
$.alert({
|
||||
title: 'Erreur',
|
||||
content: "Impossible de supprimer des transferts et des opérations en même temps !",
|
||||
backgroundDismiss: true,
|
||||
animation: 'top',
|
||||
closeAnimation: 'bottom',
|
||||
keyboardEnabled: true,
|
||||
});
|
||||
} else if (opes_to_cancel["transfers"].length > 0) {
|
||||
delete opes_to_cancel["operations"];
|
||||
this._cancel("transfer", opes_to_cancel);
|
||||
} else if (opes_to_cancel["operations"].length > 0) {
|
||||
delete opes_to_cancel["transfers"];
|
||||
this._cancel("operation", opes_to_cancel);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
KHistory.default_options = {
|
||||
container: '#history',
|
||||
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_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_opegroup: '<div class="group"><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="group"><span class="time"></span><span class="infos"></span><span class="valid_by"></span><span class="comment"></span></div>',
|
||||
template_ope: '<div class="entry"><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="entry"><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,
|
||||
}
|
||||
|
|
|
@ -5,6 +5,7 @@
|
|||
|
||||
{% block extra_head %}
|
||||
<script type="text/javascript" src="{% static 'kfet/js/history.js' %}"></script>
|
||||
<script type="text/javascript" src="{% url 'js_reverse' %}" ></script>
|
||||
<script type="text/javascript" src="{% static 'kfet/vendor/moment/moment.min.js' %}"></script>
|
||||
<script type="text/javascript" src="{% static 'kfet/vendor/moment/fr.js' %}"></script>
|
||||
<script type="text/javascript" src="{% static 'kfet/vendor/moment/moment-timezone-with-data-2012-2022.min.js' %}"></script>
|
||||
|
@ -81,7 +82,7 @@ $(document).ready(function() {
|
|||
</ul>
|
||||
</div>
|
||||
{% endif %}
|
||||
<div id="history" class="full"></div>
|
||||
<div id="history"></div>
|
||||
</section>
|
||||
</div><!-- history tab -->
|
||||
|
||||
|
@ -93,29 +94,22 @@ $(document).ready(function() {
|
|||
|
||||
khistory = new KHistory({
|
||||
display_trigramme: false,
|
||||
});
|
||||
|
||||
function getHistory() {
|
||||
var data = {
|
||||
fetch_options: {
|
||||
'accounts': [{{ account.pk }}],
|
||||
}
|
||||
});
|
||||
|
||||
$.ajax({
|
||||
dataType: "json",
|
||||
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]);
|
||||
$(document).on('keydown', function (e) {
|
||||
if (e.keyCode == 46) {
|
||||
// DEL (Suppr)
|
||||
khistory.cancel_selected()
|
||||
}
|
||||
});
|
||||
|
||||
khistory.fetch().done(function () {
|
||||
var nb_opes = khistory.$container.find('.ope:not(.canceled)').length;
|
||||
$('#nb_opes').text(nb_opes);
|
||||
});
|
||||
}
|
||||
|
||||
getHistory();
|
||||
});
|
||||
</script>
|
||||
|
||||
|
|
|
@ -5,6 +5,7 @@
|
|||
<link rel="stylesheet" type="text/css" href="{% static 'kfet/vendor/multiple-select/multiple-select.css' %}">
|
||||
<script type="text/javascript" src="{% static 'kfet/vendor/multiple-select/multiple-select.js' %}"></script>
|
||||
{{ filter_form.media }}
|
||||
<script type="text/javascript" src="{% url 'js_reverse' %}" ></script>
|
||||
<script type="text/javascript" src="{% static 'kfet/js/history.js' %}"></script>
|
||||
<script type="text/javascript" src="{% static 'kfet/vendor/moment/moment-timezone-with-data-2012-2022.min.js' %}"></script>
|
||||
{% endblock %}
|
||||
|
@ -27,6 +28,9 @@
|
|||
<li><b>Comptes</b> {{ filter_form.accounts }}</li>
|
||||
</ul>
|
||||
</div>
|
||||
<div class="buttons">
|
||||
<button class="btn btn-primary" id="btn-fetch">Valider</button>
|
||||
</div>
|
||||
</aside>
|
||||
|
||||
{% endblock %}
|
||||
|
@ -40,6 +44,8 @@
|
|||
$(document).ready(function() {
|
||||
settings = { 'subvention_cof': parseFloat({{ kfet_config.subvention_cof|unlocalize }})}
|
||||
|
||||
window.lock = 0;
|
||||
|
||||
khistory = new KHistory();
|
||||
|
||||
var $from_date = $('#id_from_date');
|
||||
|
@ -67,17 +73,8 @@ $(document).ready(function() {
|
|||
var accounts = getSelectedMultiple($accounts);
|
||||
data['accounts'] = accounts;
|
||||
|
||||
$.ajax({
|
||||
dataType: "json",
|
||||
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]);
|
||||
}
|
||||
var nb_opes = khistory.$container.find('.ope:not(.canceled)').length;
|
||||
khistory.fetch(data).done(function () {
|
||||
var nb_opes = khistory.$container.find('.entry:not(.canceled)').length;
|
||||
$('#nb_opes').text(nb_opes);
|
||||
});
|
||||
}
|
||||
|
@ -112,130 +109,17 @@ $(document).ready(function() {
|
|||
countSelected: "# sur %"
|
||||
});
|
||||
|
||||
$("input").on('dp.change change', function() {
|
||||
$("#btn-fetch").on('click', function() {
|
||||
khistory.reset();
|
||||
getHistory();
|
||||
});
|
||||
|
||||
khistory.$container.selectable({
|
||||
filter: 'div.opegroup, div.ope',
|
||||
selected: function(e, ui) {
|
||||
$(ui.selected).each(function() {
|
||||
if ($(this).hasClass('opegroup')) {
|
||||
var opegroup = $(this).data('opegroup');
|
||||
$(this).siblings('.ope').filter(function() {
|
||||
return $(this).data('opegroup') == opegroup
|
||||
}).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('ope'));
|
||||
});
|
||||
if (opes_to_cancel.length > 0)
|
||||
confirmCancel(opes_to_cancel);
|
||||
khistory.cancel_selected()
|
||||
}
|
||||
});
|
||||
|
||||
function confirmCancel(opes_to_cancel) {
|
||||
var nb = opes_to_cancel.length;
|
||||
var content = nb+" opérations vont être annulées";
|
||||
$.confirm({
|
||||
title: 'Confirmation',
|
||||
content: content,
|
||||
backgroundDismiss: true,
|
||||
animation: 'top',
|
||||
closeAnimation: 'bottom',
|
||||
keyboardEnabled: true,
|
||||
confirm: function() {
|
||||
cancelOperations(opes_to_cancel);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
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 = '') {
|
||||
var data = { 'operations' : opes_array }
|
||||
$.ajax({
|
||||
dataType: "json",
|
||||
url : "{% url 'kfet.kpsul.cancel_operations' %}",
|
||||
method : "POST",
|
||||
data : data,
|
||||
beforeSend: function ($xhr) {
|
||||
$xhr.setRequestHeader("X-CSRFToken", csrftoken);
|
||||
if (password != '')
|
||||
$xhr.setRequestHeader("KFetPassword", password);
|
||||
},
|
||||
|
||||
})
|
||||
.done(function(data) {
|
||||
khistory.$container.find('.ui-selected').removeClass('ui-selected');
|
||||
})
|
||||
.fail(function($xhr) {
|
||||
var data = $xhr.responseJSON;
|
||||
switch ($xhr.status) {
|
||||
case 403:
|
||||
requestAuth(data, function(password) {
|
||||
cancelOperations(opes_array, password);
|
||||
});
|
||||
break;
|
||||
case 400:
|
||||
displayErrors(getErrorsHtml(data));
|
||||
break;
|
||||
}
|
||||
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
getHistory();
|
||||
});
|
||||
</script>
|
||||
|
|
|
@ -189,7 +189,7 @@ $(document).ready(function() {
|
|||
// -----
|
||||
|
||||
// Lock to avoid multiple requests
|
||||
lock = 0;
|
||||
window.lock = 0;
|
||||
|
||||
// Retrieve settings
|
||||
|
||||
|
@ -479,9 +479,9 @@ $(document).ready(function() {
|
|||
var operations = $('#operation_formset');
|
||||
|
||||
function performOperations(password = '') {
|
||||
if (lock == 1)
|
||||
if (window.lock == 1)
|
||||
return false;
|
||||
lock = 1;
|
||||
window.lock = 1;
|
||||
var data = operationGroup.serialize() + '&' + operations.serialize();
|
||||
$.ajax({
|
||||
dataType: "json",
|
||||
|
@ -497,7 +497,7 @@ $(document).ready(function() {
|
|||
.done(function(data) {
|
||||
updatePreviousOp();
|
||||
coolReset();
|
||||
lock = 0;
|
||||
window.lock = 0;
|
||||
})
|
||||
.fail(function($xhr) {
|
||||
var data = $xhr.responseJSON;
|
||||
|
@ -513,7 +513,7 @@ $(document).ready(function() {
|
|||
}
|
||||
break;
|
||||
}
|
||||
lock = 0;
|
||||
window.lock = 0;
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -522,55 +522,6 @@ $(document).ready(function() {
|
|||
performOperations();
|
||||
});
|
||||
|
||||
// -----
|
||||
// Cancel operations
|
||||
// -----
|
||||
|
||||
var cancelButton = $('#cancel_operations');
|
||||
var cancelForm = $('#cancel_form');
|
||||
|
||||
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",
|
||||
data : data,
|
||||
beforeSend: function ($xhr) {
|
||||
$xhr.setRequestHeader("X-CSRFToken", csrftoken);
|
||||
if (password != '')
|
||||
$xhr.setRequestHeader("KFetPassword", password);
|
||||
},
|
||||
|
||||
})
|
||||
.done(function(data) {
|
||||
coolReset();
|
||||
lock = 0;
|
||||
})
|
||||
.fail(function($xhr) {
|
||||
var data = $xhr.responseJSON;
|
||||
switch ($xhr.status) {
|
||||
case 403:
|
||||
requestAuth(data, function(password) {
|
||||
cancelOperations(opes_array, password);
|
||||
}, triInput);
|
||||
break;
|
||||
case 400:
|
||||
displayErrors(getErrorsHtml(data));
|
||||
break;
|
||||
}
|
||||
lock = 0;
|
||||
});
|
||||
}
|
||||
|
||||
// Event listeners
|
||||
cancelButton.on('click', function() {
|
||||
cancelOperations();
|
||||
});
|
||||
|
||||
// -----
|
||||
// Articles data
|
||||
// -----
|
||||
|
@ -1189,24 +1140,12 @@ $(document).ready(function() {
|
|||
// History
|
||||
// -----
|
||||
|
||||
khistory = new KHistory();
|
||||
|
||||
function getHistory() {
|
||||
var data = {
|
||||
khistory = new KHistory({
|
||||
fetch_options: {
|
||||
from: moment().subtract(1, 'days').format('YYYY-MM-DD HH:mm:ss'),
|
||||
};
|
||||
$.ajax({
|
||||
dataType: "json",
|
||||
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]);
|
||||
}
|
||||
opesonly: true,
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
var previousop_container = $('#previous_op');
|
||||
|
||||
|
@ -1302,29 +1241,10 @@ $(document).ready(function() {
|
|||
// Cancel from history
|
||||
// -----
|
||||
|
||||
khistory.$container.selectable({
|
||||
filter: 'div.opegroup, div.ope',
|
||||
selected: function(e, ui) {
|
||||
$(ui.selected).each(function() {
|
||||
if ($(this).hasClass('opegroup')) {
|
||||
var opegroup = $(this).data('opegroup');
|
||||
$(this).siblings('.ope').filter(function() {
|
||||
return $(this).data('opegroup') == opegroup
|
||||
}).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('ope'));
|
||||
});
|
||||
if (opes_to_cancel.length > 0)
|
||||
cancelOperations(opes_to_cancel);
|
||||
khistory.cancel_selected()
|
||||
}
|
||||
});
|
||||
|
||||
|
@ -1333,16 +1253,9 @@ $(document).ready(function() {
|
|||
// -----
|
||||
|
||||
OperationWebSocket.add_handler(function(data) {
|
||||
for (var i=0; i<data['opegroups'].length; i++) {
|
||||
if (data['opegroups'][i]['add']) {
|
||||
khistory.addOpeGroup(data['opegroups'][i]);
|
||||
} else if (data['opegroups'][i]['cancellation']) {
|
||||
khistory.cancelOpeGroup(data['opegroups'][i]);
|
||||
}
|
||||
}
|
||||
for (var i=0; i<data['opes'].length; i++) {
|
||||
if (data['opes'][i]['cancellation']) {
|
||||
khistory.cancelOpe(data['opes'][i]);
|
||||
for (var i=0; i<data['groups'].length; i++) {
|
||||
if (data['groups'][i]['add']) {
|
||||
khistory.add_history_group(data['groups'][i]);
|
||||
}
|
||||
}
|
||||
for (var i=0; i<data['checkouts'].length; i++) {
|
||||
|
@ -1396,7 +1309,7 @@ $(document).ready(function() {
|
|||
khistory.reset();
|
||||
resetSettings().done(function (){
|
||||
getArticles();
|
||||
getHistory();
|
||||
khistory.fetch();
|
||||
displayAddcost();
|
||||
});
|
||||
}
|
||||
|
|
|
@ -1,9 +1,16 @@
|
|||
{% extends 'kfet/base_col_2.html' %}
|
||||
{% load staticfiles %}
|
||||
{% load l10n staticfiles widget_tweaks %}
|
||||
|
||||
{% block title %}Transferts{% endblock %}
|
||||
{% block header-title %}Transferts{% endblock %}
|
||||
|
||||
{% block extra_head %}
|
||||
<script type="text/javascript" src="{% url 'js_reverse' %}" ></script>
|
||||
<script type="text/javascript" src="{% static 'kfet/js/history.js' %}"></script>
|
||||
<script type="text/javascript" src="{% static 'kfet/vendor/moment/moment-timezone-with-data-2012-2022.min.js' %}"></script>
|
||||
{% endblock %}
|
||||
|
||||
{% block fixed %}
|
||||
|
||||
<div class="buttons">
|
||||
|
@ -16,109 +23,31 @@
|
|||
|
||||
{% block main %}
|
||||
|
||||
<div id="history">
|
||||
{% 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 %}
|
||||
</div>
|
||||
<table id="history" class="table">
|
||||
</table>
|
||||
|
||||
<script type="text/javascript">
|
||||
|
||||
$(document).ready(function() {
|
||||
|
||||
lock = 0;
|
||||
|
||||
function displayErrors(html) {
|
||||
$.alert({
|
||||
title: 'Erreurs',
|
||||
content: html,
|
||||
backgroundDismiss: true,
|
||||
animation: 'top',
|
||||
closeAnimation: 'bottom',
|
||||
keyboardEnabled: true,
|
||||
});
|
||||
}
|
||||
window.lock = 0;
|
||||
settings = { 'subvention_cof': parseFloat({{ kfet_config.subvention_cof|unlocalize }})}
|
||||
|
||||
|
||||
function cancelTransfers(transfers_array, password = '') {
|
||||
if (lock == 1)
|
||||
return false
|
||||
lock = 1;
|
||||
var data = { 'transfers' : transfers_array }
|
||||
$.ajax({
|
||||
dataType: "json",
|
||||
url : "{% url 'kfet.transfers.cancel' %}",
|
||||
method : "POST",
|
||||
data : data,
|
||||
beforeSend: function ($xhr) {
|
||||
$xhr.setRequestHeader("X-CSRFToken", csrftoken);
|
||||
if (password != '')
|
||||
$xhr.setRequestHeader("KFetPassword", password);
|
||||
},
|
||||
|
||||
})
|
||||
.done(function(data) {
|
||||
for (var i=0; i<data['canceled'].length; i++) {
|
||||
$('#history').find('.transfer[data-transfer='+data['canceled'][i]+']')
|
||||
.addClass('canceled');
|
||||
var khistory = new KHistory({
|
||||
fetch_options:{
|
||||
transfersonly: true,
|
||||
}
|
||||
$('#history').find('.ui-selected').removeClass('ui-selected');
|
||||
lock = 0;
|
||||
})
|
||||
.fail(function($xhr) {
|
||||
var data = $xhr.responseJSON;
|
||||
switch ($xhr.status) {
|
||||
case 403:
|
||||
requestAuth(data, function(password) {
|
||||
cancelTransfers(transfers_array, password);
|
||||
});
|
||||
break;
|
||||
case 400:
|
||||
displayErrors(getErrorsHtml(data));
|
||||
break;
|
||||
}
|
||||
lock = 0;
|
||||
});
|
||||
}
|
||||
|
||||
$('#history').selectable({
|
||||
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);
|
||||
khistory.cancel_selected()
|
||||
}
|
||||
});
|
||||
|
||||
khistory.fetch()
|
||||
});
|
||||
|
||||
</script>
|
||||
|
|
|
@ -3,7 +3,7 @@ from datetime import datetime, timedelta
|
|||
from decimal import Decimal
|
||||
from unittest import mock
|
||||
|
||||
from django.contrib.auth.models import Group
|
||||
from django.contrib.auth.models import Group, User
|
||||
from django.test import Client, TestCase
|
||||
from django.urls import reverse
|
||||
from django.utils import timezone
|
||||
|
@ -1997,9 +1997,10 @@ class KPsulPerformOperationsViewTests(ViewTestCaseMixin, TestCase):
|
|||
self.kpsul_consumer_mock.group_send.assert_called_once_with(
|
||||
"kfet.kpsul",
|
||||
{
|
||||
"opegroups": [
|
||||
"groups": [
|
||||
{
|
||||
"add": True,
|
||||
"type": "operation",
|
||||
"at": mock.ANY,
|
||||
"amount": Decimal("-5.00"),
|
||||
"checkout__name": "Checkout",
|
||||
|
@ -2008,7 +2009,7 @@ class KPsulPerformOperationsViewTests(ViewTestCaseMixin, TestCase):
|
|||
"is_cof": False,
|
||||
"on_acc__trigramme": "000",
|
||||
"valid_by__trigramme": None,
|
||||
"opes": [
|
||||
"entries": [
|
||||
{
|
||||
"id": operation.pk,
|
||||
"addcost_amount": None,
|
||||
|
@ -2269,9 +2270,10 @@ class KPsulPerformOperationsViewTests(ViewTestCaseMixin, TestCase):
|
|||
self.kpsul_consumer_mock.group_send.assert_called_once_with(
|
||||
"kfet.kpsul",
|
||||
{
|
||||
"opegroups": [
|
||||
"groups": [
|
||||
{
|
||||
"add": True,
|
||||
"type": "operation",
|
||||
"at": mock.ANY,
|
||||
"amount": Decimal("10.75"),
|
||||
"checkout__name": "Checkout",
|
||||
|
@ -2280,7 +2282,7 @@ class KPsulPerformOperationsViewTests(ViewTestCaseMixin, TestCase):
|
|||
"is_cof": False,
|
||||
"on_acc__trigramme": "000",
|
||||
"valid_by__trigramme": "100",
|
||||
"opes": [
|
||||
"entries": [
|
||||
{
|
||||
"id": operation.pk,
|
||||
"addcost_amount": None,
|
||||
|
@ -2443,9 +2445,10 @@ class KPsulPerformOperationsViewTests(ViewTestCaseMixin, TestCase):
|
|||
self.kpsul_consumer_mock.group_send.assert_called_once_with(
|
||||
"kfet.kpsul",
|
||||
{
|
||||
"opegroups": [
|
||||
"groups": [
|
||||
{
|
||||
"add": True,
|
||||
"type": "operation",
|
||||
"at": mock.ANY,
|
||||
"amount": Decimal("-10.75"),
|
||||
"checkout__name": "Checkout",
|
||||
|
@ -2454,7 +2457,7 @@ class KPsulPerformOperationsViewTests(ViewTestCaseMixin, TestCase):
|
|||
"is_cof": False,
|
||||
"on_acc__trigramme": "000",
|
||||
"valid_by__trigramme": None,
|
||||
"opes": [
|
||||
"entries": [
|
||||
{
|
||||
"id": operation.pk,
|
||||
"addcost_amount": None,
|
||||
|
@ -2601,9 +2604,10 @@ class KPsulPerformOperationsViewTests(ViewTestCaseMixin, TestCase):
|
|||
self.kpsul_consumer_mock.group_send.assert_called_once_with(
|
||||
"kfet.kpsul",
|
||||
{
|
||||
"opegroups": [
|
||||
"groups": [
|
||||
{
|
||||
"add": True,
|
||||
"type": "operation",
|
||||
"at": mock.ANY,
|
||||
"amount": Decimal("10.75"),
|
||||
"checkout__name": "Checkout",
|
||||
|
@ -2612,7 +2616,7 @@ class KPsulPerformOperationsViewTests(ViewTestCaseMixin, TestCase):
|
|||
"is_cof": False,
|
||||
"on_acc__trigramme": "000",
|
||||
"valid_by__trigramme": "100",
|
||||
"opes": [
|
||||
"entries": [
|
||||
{
|
||||
"id": operation.pk,
|
||||
"addcost_amount": None,
|
||||
|
@ -2712,9 +2716,9 @@ class KPsulPerformOperationsViewTests(ViewTestCaseMixin, TestCase):
|
|||
self.checkout.refresh_from_db()
|
||||
self.assertEqual(self.checkout.balance, Decimal("100.00"))
|
||||
|
||||
ws_data_ope = self.kpsul_consumer_mock.group_send.call_args[0][1]["opegroups"][
|
||||
0
|
||||
]["opes"][0]
|
||||
ws_data_ope = self.kpsul_consumer_mock.group_send.call_args[0][1]["groups"][0][
|
||||
"entries"
|
||||
][0]
|
||||
self.assertEqual(ws_data_ope["addcost_amount"], Decimal("1.00"))
|
||||
self.assertEqual(ws_data_ope["addcost_for__trigramme"], "ADD")
|
||||
|
||||
|
@ -2752,9 +2756,9 @@ class KPsulPerformOperationsViewTests(ViewTestCaseMixin, TestCase):
|
|||
self.checkout.refresh_from_db()
|
||||
self.assertEqual(self.checkout.balance, Decimal("100.00"))
|
||||
|
||||
ws_data_ope = self.kpsul_consumer_mock.group_send.call_args[0][1]["opegroups"][
|
||||
0
|
||||
]["opes"][0]
|
||||
ws_data_ope = self.kpsul_consumer_mock.group_send.call_args[0][1]["groups"][0][
|
||||
"entries"
|
||||
][0]
|
||||
self.assertEqual(ws_data_ope["addcost_amount"], Decimal("0.80"))
|
||||
self.assertEqual(ws_data_ope["addcost_for__trigramme"], "ADD")
|
||||
|
||||
|
@ -2790,9 +2794,9 @@ class KPsulPerformOperationsViewTests(ViewTestCaseMixin, TestCase):
|
|||
self.checkout.refresh_from_db()
|
||||
self.assertEqual(self.checkout.balance, Decimal("106.00"))
|
||||
|
||||
ws_data_ope = self.kpsul_consumer_mock.group_send.call_args[0][1]["opegroups"][
|
||||
0
|
||||
]["opes"][0]
|
||||
ws_data_ope = self.kpsul_consumer_mock.group_send.call_args[0][1]["groups"][0][
|
||||
"entries"
|
||||
][0]
|
||||
self.assertEqual(ws_data_ope["addcost_amount"], Decimal("1.00"))
|
||||
self.assertEqual(ws_data_ope["addcost_for__trigramme"], "ADD")
|
||||
|
||||
|
@ -2826,9 +2830,9 @@ class KPsulPerformOperationsViewTests(ViewTestCaseMixin, TestCase):
|
|||
self.accounts["addcost"].refresh_from_db()
|
||||
self.assertEqual(self.accounts["addcost"].balance, Decimal("15.00"))
|
||||
|
||||
ws_data_ope = self.kpsul_consumer_mock.group_send.call_args[0][1]["opegroups"][
|
||||
0
|
||||
]["opes"][0]
|
||||
ws_data_ope = self.kpsul_consumer_mock.group_send.call_args[0][1]["groups"][0][
|
||||
"entries"
|
||||
][0]
|
||||
self.assertEqual(ws_data_ope["addcost_amount"], None)
|
||||
self.assertEqual(ws_data_ope["addcost_for__trigramme"], None)
|
||||
|
||||
|
@ -2861,9 +2865,9 @@ class KPsulPerformOperationsViewTests(ViewTestCaseMixin, TestCase):
|
|||
self.accounts["addcost"].refresh_from_db()
|
||||
self.assertEqual(self.accounts["addcost"].balance, Decimal("0.00"))
|
||||
|
||||
ws_data_ope = self.kpsul_consumer_mock.group_send.call_args[0][1]["opegroups"][
|
||||
0
|
||||
]["opes"][0]
|
||||
ws_data_ope = self.kpsul_consumer_mock.group_send.call_args[0][1]["groups"][0][
|
||||
"entries"
|
||||
][0]
|
||||
self.assertEqual(ws_data_ope["addcost_amount"], None)
|
||||
self.assertEqual(ws_data_ope["addcost_for__trigramme"], None)
|
||||
|
||||
|
@ -3170,9 +3174,10 @@ class KPsulPerformOperationsViewTests(ViewTestCaseMixin, TestCase):
|
|||
self.kpsul_consumer_mock.group_send.assert_called_once_with(
|
||||
"kfet.kpsul",
|
||||
{
|
||||
"opegroups": [
|
||||
"groups": [
|
||||
{
|
||||
"add": True,
|
||||
"type": "operation",
|
||||
"at": mock.ANY,
|
||||
"amount": Decimal("-9.00"),
|
||||
"checkout__name": "Checkout",
|
||||
|
@ -3181,7 +3186,7 @@ class KPsulPerformOperationsViewTests(ViewTestCaseMixin, TestCase):
|
|||
"is_cof": False,
|
||||
"on_acc__trigramme": "000",
|
||||
"valid_by__trigramme": None,
|
||||
"opes": [
|
||||
"entries": [
|
||||
{
|
||||
"id": operation_list[0].pk,
|
||||
"addcost_amount": None,
|
||||
|
@ -3234,7 +3239,7 @@ class KPsulCancelOperationsViewTests(ViewTestCaseMixin, TestCase):
|
|||
|
||||
"""
|
||||
|
||||
url_name = "kfet.kpsul.cancel_operations"
|
||||
url_name = "kfet.operations.cancel"
|
||||
url_expected = "/k-fet/k-psul/cancel_operations"
|
||||
|
||||
http_methods = ["POST"]
|
||||
|
@ -3353,7 +3358,26 @@ class KPsulCancelOperationsViewTests(ViewTestCaseMixin, TestCase):
|
|||
)
|
||||
|
||||
self.assertDictEqual(
|
||||
json_data, {"canceled": [operation.pk], "errors": {}, "warnings": {}}
|
||||
json_data,
|
||||
{
|
||||
"canceled": [
|
||||
{
|
||||
"id": operation.id,
|
||||
# l'encodage des dates en JSON est relou...
|
||||
"canceled_at": mock.ANY,
|
||||
"canceled_by__trigramme": None,
|
||||
}
|
||||
],
|
||||
"errors": {},
|
||||
"warnings": {},
|
||||
"opegroups_to_update": [
|
||||
{
|
||||
"id": group.pk,
|
||||
"amount": str(group.amount),
|
||||
"is_cof": group.is_cof,
|
||||
}
|
||||
],
|
||||
},
|
||||
)
|
||||
|
||||
self.account.refresh_from_db()
|
||||
|
@ -3365,26 +3389,7 @@ class KPsulCancelOperationsViewTests(ViewTestCaseMixin, TestCase):
|
|||
|
||||
self.kpsul_consumer_mock.group_send.assert_called_with(
|
||||
"kfet.kpsul",
|
||||
{
|
||||
"opegroups": [
|
||||
{
|
||||
"cancellation": True,
|
||||
"id": group.pk,
|
||||
"amount": Decimal("0.00"),
|
||||
"is_cof": False,
|
||||
}
|
||||
],
|
||||
"opes": [
|
||||
{
|
||||
"cancellation": True,
|
||||
"id": operation.pk,
|
||||
"canceled_by__trigramme": None,
|
||||
"canceled_at": self.now + timedelta(seconds=15),
|
||||
}
|
||||
],
|
||||
"checkouts": [],
|
||||
"articles": [{"id": self.article.pk, "stock": 22}],
|
||||
},
|
||||
{"checkouts": [], "articles": [{"id": self.article.pk, "stock": 22}]},
|
||||
)
|
||||
|
||||
def test_purchase_with_addcost(self):
|
||||
|
@ -3541,7 +3546,26 @@ class KPsulCancelOperationsViewTests(ViewTestCaseMixin, TestCase):
|
|||
)
|
||||
|
||||
self.assertDictEqual(
|
||||
json_data, {"canceled": [operation.pk], "errors": {}, "warnings": {}}
|
||||
json_data,
|
||||
{
|
||||
"canceled": [
|
||||
{
|
||||
"id": operation.id,
|
||||
# l'encodage des dates en JSON est relou...
|
||||
"canceled_at": mock.ANY,
|
||||
"canceled_by__trigramme": None,
|
||||
}
|
||||
],
|
||||
"errors": {},
|
||||
"warnings": {},
|
||||
"opegroups_to_update": [
|
||||
{
|
||||
"id": group.pk,
|
||||
"amount": str(group.amount),
|
||||
"is_cof": group.is_cof,
|
||||
}
|
||||
],
|
||||
},
|
||||
)
|
||||
|
||||
self.account.refresh_from_db()
|
||||
|
@ -3554,22 +3578,6 @@ class KPsulCancelOperationsViewTests(ViewTestCaseMixin, TestCase):
|
|||
self.kpsul_consumer_mock.group_send.assert_called_with(
|
||||
"kfet.kpsul",
|
||||
{
|
||||
"opegroups": [
|
||||
{
|
||||
"cancellation": True,
|
||||
"id": group.pk,
|
||||
"amount": Decimal("0.00"),
|
||||
"is_cof": False,
|
||||
}
|
||||
],
|
||||
"opes": [
|
||||
{
|
||||
"cancellation": True,
|
||||
"id": operation.pk,
|
||||
"canceled_by__trigramme": None,
|
||||
"canceled_at": self.now + timedelta(seconds=15),
|
||||
}
|
||||
],
|
||||
"checkouts": [{"id": self.checkout.pk, "balance": Decimal("89.25")}],
|
||||
"articles": [],
|
||||
},
|
||||
|
@ -3625,7 +3633,26 @@ class KPsulCancelOperationsViewTests(ViewTestCaseMixin, TestCase):
|
|||
)
|
||||
|
||||
self.assertDictEqual(
|
||||
json_data, {"canceled": [operation.pk], "errors": {}, "warnings": {}}
|
||||
json_data,
|
||||
{
|
||||
"canceled": [
|
||||
{
|
||||
"id": operation.id,
|
||||
# l'encodage des dates en JSON est relou...
|
||||
"canceled_at": mock.ANY,
|
||||
"canceled_by__trigramme": None,
|
||||
}
|
||||
],
|
||||
"errors": {},
|
||||
"warnings": {},
|
||||
"opegroups_to_update": [
|
||||
{
|
||||
"id": group.pk,
|
||||
"amount": str(group.amount),
|
||||
"is_cof": group.is_cof,
|
||||
}
|
||||
],
|
||||
},
|
||||
)
|
||||
|
||||
self.account.refresh_from_db()
|
||||
|
@ -3638,22 +3665,6 @@ class KPsulCancelOperationsViewTests(ViewTestCaseMixin, TestCase):
|
|||
self.kpsul_consumer_mock.group_send.assert_called_with(
|
||||
"kfet.kpsul",
|
||||
{
|
||||
"opegroups": [
|
||||
{
|
||||
"cancellation": True,
|
||||
"id": group.pk,
|
||||
"amount": Decimal("0.00"),
|
||||
"is_cof": False,
|
||||
}
|
||||
],
|
||||
"opes": [
|
||||
{
|
||||
"cancellation": True,
|
||||
"id": operation.pk,
|
||||
"canceled_by__trigramme": None,
|
||||
"canceled_at": self.now + timedelta(seconds=15),
|
||||
}
|
||||
],
|
||||
"checkouts": [{"id": self.checkout.pk, "balance": Decimal("110.75")}],
|
||||
"articles": [],
|
||||
},
|
||||
|
@ -3709,7 +3720,26 @@ class KPsulCancelOperationsViewTests(ViewTestCaseMixin, TestCase):
|
|||
)
|
||||
|
||||
self.assertDictEqual(
|
||||
json_data, {"canceled": [operation.pk], "errors": {}, "warnings": {}}
|
||||
json_data,
|
||||
{
|
||||
"canceled": [
|
||||
{
|
||||
"id": operation.id,
|
||||
# l'encodage des dates en JSON est relou...
|
||||
"canceled_at": mock.ANY,
|
||||
"canceled_by__trigramme": None,
|
||||
}
|
||||
],
|
||||
"errors": {},
|
||||
"warnings": {},
|
||||
"opegroups_to_update": [
|
||||
{
|
||||
"id": group.pk,
|
||||
"amount": str(group.amount),
|
||||
"is_cof": group.is_cof,
|
||||
}
|
||||
],
|
||||
},
|
||||
)
|
||||
|
||||
self.account.refresh_from_db()
|
||||
|
@ -3720,27 +3750,7 @@ class KPsulCancelOperationsViewTests(ViewTestCaseMixin, TestCase):
|
|||
self.assertEqual(self.checkout.balance, Decimal("100.00"))
|
||||
|
||||
self.kpsul_consumer_mock.group_send.assert_called_with(
|
||||
"kfet.kpsul",
|
||||
{
|
||||
"opegroups": [
|
||||
{
|
||||
"cancellation": True,
|
||||
"id": group.pk,
|
||||
"amount": Decimal("0.00"),
|
||||
"is_cof": False,
|
||||
}
|
||||
],
|
||||
"opes": [
|
||||
{
|
||||
"cancellation": True,
|
||||
"id": operation.pk,
|
||||
"canceled_by__trigramme": None,
|
||||
"canceled_at": self.now + timedelta(seconds=15),
|
||||
}
|
||||
],
|
||||
"checkouts": [],
|
||||
"articles": [],
|
||||
},
|
||||
"kfet.kpsul", {"checkouts": [], "articles": []},
|
||||
)
|
||||
|
||||
@mock.patch("django.utils.timezone.now")
|
||||
|
@ -3961,13 +3971,33 @@ class KPsulCancelOperationsViewTests(ViewTestCaseMixin, TestCase):
|
|||
group.refresh_from_db()
|
||||
self.assertEqual(group.amount, Decimal("10.75"))
|
||||
self.assertEqual(group.opes.exclude(canceled_at=None).count(), 3)
|
||||
|
||||
self.maxDiff = None
|
||||
self.assertDictEqual(
|
||||
json_data,
|
||||
{
|
||||
"canceled": [operation1.pk, operation2.pk],
|
||||
"warnings": {"already_canceled": [operation3.pk]},
|
||||
"canceled": [
|
||||
{
|
||||
"id": operation1.id,
|
||||
# l'encodage des dates en JSON est relou...
|
||||
"canceled_at": mock.ANY,
|
||||
"canceled_by__trigramme": None,
|
||||
},
|
||||
{
|
||||
"id": operation2.id,
|
||||
# l'encodage des dates en JSON est relou...
|
||||
"canceled_at": mock.ANY,
|
||||
"canceled_by__trigramme": None,
|
||||
},
|
||||
],
|
||||
"errors": {},
|
||||
"warnings": {"already_canceled": [operation3.pk]},
|
||||
"opegroups_to_update": [
|
||||
{
|
||||
"id": group.pk,
|
||||
"amount": str(group.amount),
|
||||
"is_cof": group.is_cof,
|
||||
}
|
||||
],
|
||||
},
|
||||
)
|
||||
|
||||
|
@ -4121,12 +4151,18 @@ class HistoryJSONViewTests(ViewTestCaseMixin, TestCase):
|
|||
url_expected = "/k-fet/history.json"
|
||||
|
||||
auth_user = "user"
|
||||
auth_forbidden = [None]
|
||||
auth_forbidden = [None, "noaccount"]
|
||||
|
||||
def test_ok(self):
|
||||
r = self.client.post(self.url)
|
||||
self.assertEqual(r.status_code, 200)
|
||||
|
||||
def get_users_extra(self):
|
||||
noaccount = User.objects.create(username="noaccount")
|
||||
noaccount.set_password("noaccount")
|
||||
noaccount.save()
|
||||
return {"noaccount": noaccount}
|
||||
|
||||
|
||||
class AccountReadJSONViewTests(ViewTestCaseMixin, TestCase):
|
||||
url_name = "kfet.account.read.json"
|
||||
|
|
|
@ -219,8 +219,8 @@ urlpatterns = [
|
|||
),
|
||||
path(
|
||||
"k-psul/cancel_operations",
|
||||
views.kpsul_cancel_operations,
|
||||
name="kfet.kpsul.cancel_operations",
|
||||
views.cancel_operations,
|
||||
name="kfet.operations.cancel",
|
||||
),
|
||||
path(
|
||||
"k-psul/articles_data",
|
||||
|
@ -252,7 +252,7 @@ urlpatterns = [
|
|||
# -----
|
||||
# Transfers urls
|
||||
# -----
|
||||
path("transfers/", views.transfers, name="kfet.transfers"),
|
||||
path("transfers/", views.TransferView.as_view(), name="kfet.transfers"),
|
||||
path("transfers/new", views.transfers_create, name="kfet.transfers.create"),
|
||||
path("transfers/perform", views.perform_transfers, name="kfet.transfers.perform"),
|
||||
path("transfers/cancel", views.cancel_transfers, name="kfet.transfers.cancel"),
|
||||
|
|
160
kfet/views.py
160
kfet/views.py
|
@ -12,7 +12,7 @@ from django.contrib.auth.mixins import PermissionRequiredMixin
|
|||
from django.contrib.auth.models import Permission, User
|
||||
from django.contrib.messages.views import SuccessMessageMixin
|
||||
from django.db import transaction
|
||||
from django.db.models import Count, F, Prefetch, Sum
|
||||
from django.db.models import Count, F, Prefetch, Q, Sum
|
||||
from django.forms import formset_factory
|
||||
from django.http import Http404, JsonResponse
|
||||
from django.shortcuts import get_object_or_404, redirect, render
|
||||
|
@ -1156,9 +1156,10 @@ def kpsul_perform_operations(request):
|
|||
|
||||
# Websocket data
|
||||
websocket_data = {}
|
||||
websocket_data["opegroups"] = [
|
||||
websocket_data["groups"] = [
|
||||
{
|
||||
"add": True,
|
||||
"type": "operation",
|
||||
"id": operationgroup.pk,
|
||||
"amount": operationgroup.amount,
|
||||
"checkout__name": operationgroup.checkout.name,
|
||||
|
@ -1169,7 +1170,7 @@ def kpsul_perform_operations(request):
|
|||
operationgroup.valid_by and operationgroup.valid_by.trigramme or None
|
||||
),
|
||||
"on_acc__trigramme": operationgroup.on_acc.trigramme,
|
||||
"opes": [],
|
||||
"entries": [],
|
||||
}
|
||||
]
|
||||
for operation in operations:
|
||||
|
@ -1187,7 +1188,7 @@ def kpsul_perform_operations(request):
|
|||
"canceled_by__trigramme": None,
|
||||
"canceled_at": None,
|
||||
}
|
||||
websocket_data["opegroups"][0]["opes"].append(ope_data)
|
||||
websocket_data["groups"][0]["entries"].append(ope_data)
|
||||
# Need refresh from db cause we used update on queryset
|
||||
operationgroup.checkout.refresh_from_db()
|
||||
websocket_data["checkouts"] = [
|
||||
|
@ -1207,7 +1208,7 @@ def kpsul_perform_operations(request):
|
|||
|
||||
@teamkfet_required
|
||||
@kfet_password_auth
|
||||
def kpsul_cancel_operations(request):
|
||||
def cancel_operations(request):
|
||||
# Pour la réponse
|
||||
data = {"canceled": [], "warnings": {}, "errors": {}}
|
||||
|
||||
|
@ -1363,7 +1364,11 @@ def kpsul_cancel_operations(request):
|
|||
.filter(pk__in=opegroups_pk)
|
||||
.order_by("pk")
|
||||
)
|
||||
opes = sorted(opes)
|
||||
opes = (
|
||||
Operation.objects.values("id", "canceled_at", "canceled_by__trigramme")
|
||||
.filter(pk__in=opes)
|
||||
.order_by("pk")
|
||||
)
|
||||
checkouts_pk = [checkout.pk for checkout in to_checkouts_balances]
|
||||
checkouts = (
|
||||
Checkout.objects.values("id", "balance")
|
||||
|
@ -1374,27 +1379,7 @@ def kpsul_cancel_operations(request):
|
|||
articles = Article.objects.values("id", "stock").filter(pk__in=articles_pk)
|
||||
|
||||
# Websocket data
|
||||
websocket_data = {"opegroups": [], "opes": [], "checkouts": [], "articles": []}
|
||||
|
||||
for opegroup in opegroups:
|
||||
websocket_data["opegroups"].append(
|
||||
{
|
||||
"cancellation": True,
|
||||
"id": opegroup["id"],
|
||||
"amount": opegroup["amount"],
|
||||
"is_cof": opegroup["is_cof"],
|
||||
}
|
||||
)
|
||||
canceled_by__trigramme = canceled_by and canceled_by.trigramme or None
|
||||
for ope in opes:
|
||||
websocket_data["opes"].append(
|
||||
{
|
||||
"cancellation": True,
|
||||
"id": ope,
|
||||
"canceled_by__trigramme": canceled_by__trigramme,
|
||||
"canceled_at": canceled_at,
|
||||
}
|
||||
)
|
||||
websocket_data = {"checkouts": [], "articles": []}
|
||||
for checkout in checkouts:
|
||||
websocket_data["checkouts"].append(
|
||||
{"id": checkout["id"], "balance": checkout["balance"]}
|
||||
|
@ -1405,7 +1390,8 @@ def kpsul_cancel_operations(request):
|
|||
)
|
||||
consumers.KPsul.group_send("kfet.kpsul", websocket_data)
|
||||
|
||||
data["canceled"] = opes
|
||||
data["canceled"] = list(opes)
|
||||
data["opegroups_to_update"] = list(opegroups)
|
||||
if opes_already_canceled:
|
||||
data["warnings"]["already_canceled"] = opes_already_canceled
|
||||
return JsonResponse(data)
|
||||
|
@ -1416,49 +1402,86 @@ def history_json(request):
|
|||
# Récupération des paramètres
|
||||
from_date = request.POST.get("from", None)
|
||||
to_date = request.POST.get("to", None)
|
||||
limit = request.POST.get("limit", None)
|
||||
checkouts = request.POST.getlist("checkouts[]", None)
|
||||
accounts = request.POST.getlist("accounts[]", None)
|
||||
transfers_only = request.POST.get("transfersonly", False)
|
||||
opes_only = request.POST.get("opesonly", False)
|
||||
|
||||
# Construction de la requête (sur les transferts) pour le prefetch
|
||||
|
||||
transfer_queryset_prefetch = Transfer.objects.select_related(
|
||||
"from_acc", "to_acc", "canceled_by"
|
||||
)
|
||||
|
||||
# Le check sur les comptes est dans le prefetch pour les transferts
|
||||
if accounts:
|
||||
transfer_queryset_prefetch = transfer_queryset_prefetch.filter(
|
||||
Q(from_acc__in=accounts) | Q(to_acc__in=accounts)
|
||||
)
|
||||
|
||||
if not request.user.has_perm("kfet.is_team"):
|
||||
try:
|
||||
acc = request.user.profile.account_kfet
|
||||
transfer_queryset_prefetch = transfer_queryset_prefetch.filter(
|
||||
Q(from_acc=acc) | Q(to_acc=acc)
|
||||
)
|
||||
except Account.DoesNotExist:
|
||||
return JsonResponse({}, status=403)
|
||||
|
||||
transfer_prefetch = Prefetch(
|
||||
"transfers", queryset=transfer_queryset_prefetch, to_attr="filtered_transfers"
|
||||
)
|
||||
|
||||
# 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(
|
||||
"article", "canceled_by", "addcost_for"
|
||||
)
|
||||
ope_prefetch = Prefetch("opes", queryset=ope_queryset_prefetch)
|
||||
|
||||
# Construction de la requête principale
|
||||
opegroups = (
|
||||
OperationGroup.objects.prefetch_related(
|
||||
Prefetch("opes", queryset=queryset_prefetch)
|
||||
)
|
||||
OperationGroup.objects.prefetch_related(ope_prefetch)
|
||||
.select_related("on_acc", "valid_by")
|
||||
.order_by("at")
|
||||
)
|
||||
transfergroups = (
|
||||
TransferGroup.objects.prefetch_related(transfer_prefetch)
|
||||
.select_related("valid_by")
|
||||
.order_by("at")
|
||||
)
|
||||
|
||||
# Application des filtres
|
||||
if from_date:
|
||||
opegroups = opegroups.filter(at__gte=from_date)
|
||||
transfergroups = transfergroups.filter(at__gte=from_date)
|
||||
if to_date:
|
||||
opegroups = opegroups.filter(at__lt=to_date)
|
||||
transfergroups = transfergroups.filter(at__lt=to_date)
|
||||
if checkouts:
|
||||
opegroups = opegroups.filter(checkout_id__in=checkouts)
|
||||
opegroups = opegroups.filter(checkout__in=checkouts)
|
||||
transfergroups = TransferGroup.objects.none()
|
||||
if transfers_only:
|
||||
opegroups = OperationGroup.objects.none()
|
||||
if opes_only:
|
||||
transfergroups = TransferGroup.objects.none()
|
||||
if accounts:
|
||||
opegroups = opegroups.filter(on_acc_id__in=accounts)
|
||||
opegroups = opegroups.filter(on_acc__in=accounts)
|
||||
# Un non-membre de l'équipe n'a que accès à son historique
|
||||
if not request.user.has_perm("kfet.is_team"):
|
||||
opegroups = opegroups.filter(on_acc=request.user.profile.account_kfet)
|
||||
if limit:
|
||||
opegroups = opegroups[:limit]
|
||||
|
||||
# Construction de la réponse
|
||||
opegroups_list = []
|
||||
history_groups = []
|
||||
for opegroup in opegroups:
|
||||
opegroup_dict = {
|
||||
"type": "operation",
|
||||
"id": opegroup.id,
|
||||
"amount": opegroup.amount,
|
||||
"at": opegroup.at,
|
||||
"checkout_id": opegroup.checkout_id,
|
||||
"is_cof": opegroup.is_cof,
|
||||
"comment": opegroup.comment,
|
||||
"opes": [],
|
||||
"entries": [],
|
||||
"on_acc__trigramme": opegroup.on_acc and opegroup.on_acc.trigramme or None,
|
||||
}
|
||||
if request.user.has_perm("kfet.is_team"):
|
||||
|
@ -1482,9 +1505,40 @@ def history_json(request):
|
|||
ope_dict["canceled_by__trigramme"] = (
|
||||
ope.canceled_by and ope.canceled_by.trigramme or None
|
||||
)
|
||||
opegroup_dict["opes"].append(ope_dict)
|
||||
opegroups_list.append(opegroup_dict)
|
||||
return JsonResponse({"opegroups": opegroups_list})
|
||||
opegroup_dict["entries"].append(ope_dict)
|
||||
history_groups.append(opegroup_dict)
|
||||
for transfergroup in transfergroups:
|
||||
if transfergroup.filtered_transfers:
|
||||
transfergroup_dict = {
|
||||
"type": "transfer",
|
||||
"id": transfergroup.id,
|
||||
"at": transfergroup.at,
|
||||
"comment": transfergroup.comment,
|
||||
"entries": [],
|
||||
}
|
||||
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["entries"].append(transfer_dict)
|
||||
history_groups.append(transfergroup_dict)
|
||||
|
||||
history_groups.sort(key=lambda group: group["at"])
|
||||
|
||||
return JsonResponse({"groups": history_groups})
|
||||
|
||||
|
||||
@teamkfet_required
|
||||
|
@ -1544,18 +1598,9 @@ config_update = permission_required("kfet.change_config")(SettingsUpdate.as_view
|
|||
# -----
|
||||
|
||||
|
||||
@teamkfet_required
|
||||
def transfers(request):
|
||||
transfers_pre = Prefetch(
|
||||
"transfers", queryset=(Transfer.objects.select_related("from_acc", "to_acc"))
|
||||
)
|
||||
|
||||
transfergroups = (
|
||||
TransferGroup.objects.select_related("valid_by")
|
||||
.prefetch_related(transfers_pre)
|
||||
.order_by("-at")
|
||||
)
|
||||
return render(request, "kfet/transfers.html", {"transfergroups": transfergroups})
|
||||
@method_decorator(teamkfet_required, name="dispatch")
|
||||
class TransferView(TemplateView):
|
||||
template_name = "kfet/transfers.html"
|
||||
|
||||
|
||||
@teamkfet_required
|
||||
|
@ -1746,7 +1791,12 @@ def cancel_transfers(request):
|
|||
elif hasattr(account, "negative") and not account.negative.balance_offset:
|
||||
account.negative.delete()
|
||||
|
||||
data["canceled"] = transfers
|
||||
transfers = (
|
||||
Transfer.objects.values("id", "canceled_at", "canceled_by__trigramme")
|
||||
.filter(pk__in=transfers)
|
||||
.order_by("pk")
|
||||
)
|
||||
data["canceled"] = list(transfers)
|
||||
if transfers_already_canceled:
|
||||
data["warnings"]["already_canceled"] = transfers_already_canceled
|
||||
return JsonResponse(data)
|
||||
|
|
Loading…
Reference in a new issue