Ajout faire des transferts
This commit is contained in:
parent
9b548c9e45
commit
27b0e3737d
9 changed files with 445 additions and 103 deletions
|
@ -3,10 +3,12 @@ from django import forms
|
|||
from django.core.exceptions import ValidationError
|
||||
from django.contrib.auth.models import User, Group, Permission
|
||||
from django.contrib.contenttypes.models import ContentType
|
||||
from django.forms import modelformset_factory
|
||||
from django.forms import modelformset_factory, inlineformset_factory
|
||||
from django.forms.models import BaseInlineFormSet
|
||||
from django.utils import timezone
|
||||
from kfet.models import (Account, Checkout, Article, OperationGroup, Operation,
|
||||
CheckoutStatement, ArticleCategory, Settings, AccountNegative)
|
||||
CheckoutStatement, ArticleCategory, Settings, AccountNegative, Transfer,
|
||||
TransferGroup)
|
||||
from gestioncof.models import CofProfile
|
||||
|
||||
# -----
|
||||
|
@ -346,3 +348,39 @@ class SettingsForm(forms.ModelForm):
|
|||
class FilterHistoryForm(forms.Form):
|
||||
checkouts = forms.ModelMultipleChoiceField(queryset = Checkout.objects.all())
|
||||
accounts = forms.ModelMultipleChoiceField(queryset = Account.objects.all())
|
||||
|
||||
# -----
|
||||
# Transfer forms
|
||||
# -----
|
||||
|
||||
class TransferGroupForm(forms.ModelForm):
|
||||
class Meta:
|
||||
model = TransferGroup
|
||||
fields = ['comment']
|
||||
|
||||
class TransferForm(forms.ModelForm):
|
||||
from_acc = forms.ModelChoiceField(
|
||||
queryset = Account.objects.exclude(trigramme__in=['LIQ', '#13']),
|
||||
widget = forms.HiddenInput()
|
||||
)
|
||||
to_acc = forms.ModelChoiceField(
|
||||
queryset = Account.objects.exclude(trigramme__in=['LIQ', '#13']),
|
||||
widget = forms.HiddenInput()
|
||||
)
|
||||
|
||||
def clean_amount(self):
|
||||
amount = self.cleaned_data['amount']
|
||||
if amount <= 0:
|
||||
raise forms.ValidationError("Montant invalide")
|
||||
return amount
|
||||
|
||||
class Meta:
|
||||
model = Transfer
|
||||
fields = ['from_acc', 'to_acc', 'amount']
|
||||
|
||||
TransferFormSet = modelformset_factory(
|
||||
Transfer,
|
||||
form = TransferForm,
|
||||
min_num = 1, validate_min = True,
|
||||
extra = 9,
|
||||
)
|
||||
|
|
|
@ -101,12 +101,9 @@ class Account(models.Model):
|
|||
data['is_free'] = True
|
||||
return data
|
||||
|
||||
def perms_to_perform_operation(self, amount, overdraft_duration_max=None, \
|
||||
overdraft_amount_max=None):
|
||||
if overdraft_duration_max is None:
|
||||
overdraft_duration_max = Settings.OVERDRAFT_DURATION()
|
||||
if overdraft_amount_max is None:
|
||||
overdraft_amount_max = Settings.OVERDRAFT_AMOUNT()
|
||||
def perms_to_perform_operation(self, amount):
|
||||
overdraft_duration_max = Settings.OVERDRAFT_DURATION()
|
||||
overdraft_amount_max = Settings.OVERDRAFT_AMOUNT()
|
||||
perms = set()
|
||||
stop_ope = False
|
||||
# Checking is cash account
|
||||
|
@ -572,17 +569,27 @@ class Settings(models.Model):
|
|||
|
||||
@staticmethod
|
||||
def OVERDRAFT_DURATION():
|
||||
overdraft_duration = cache.get('OVERDRAFT_DURATION')
|
||||
if overdraft_duration:
|
||||
return overdraft_duration
|
||||
try:
|
||||
return Settings.setting_inst("OVERDRAFT_DURATION").value_duration
|
||||
overdraft_duration = Settings.setting_inst("OVERDRAFT_DURATION").value_duration
|
||||
except Settings.DoesNotExist:
|
||||
return timedelta()
|
||||
overdraft_duration = timedelta()
|
||||
cache.set('OVERDRAFT_DURATION', overdraft_duration)
|
||||
return overdraft_duration
|
||||
|
||||
@staticmethod
|
||||
def OVERDRAFT_AMOUNT():
|
||||
overdraft_amount = cache.get('OVERDRAFT_AMOUNT')
|
||||
if overdraft_amount:
|
||||
return overdraft_amount
|
||||
try:
|
||||
return Settings.setting_inst("OVERDRAFT_AMOUNT").value_decimal
|
||||
overdraft_amount = Settings.setting_inst("OVERDRAFT_AMOUNT").value_decimal
|
||||
except Settings.DoesNotExist:
|
||||
return 0
|
||||
overdraft_amount = 0
|
||||
cache.set('OVERDRAFT_AMOUNT', overdraft_amount)
|
||||
return overdraft_amount
|
||||
|
||||
def CANCEL_DURATION():
|
||||
try:
|
||||
|
@ -614,5 +621,11 @@ class Settings(models.Model):
|
|||
s.value_duration = timedelta(minutes=5) # 5min
|
||||
s.save()
|
||||
|
||||
@staticmethod
|
||||
def empty_cache():
|
||||
cache.delete_many([
|
||||
'SUBVENTION_COF','OVERDRAFT_DURATION', 'OVERDRAFT_AMOUNT',
|
||||
])
|
||||
|
||||
class GenericTeamToken(models.Model):
|
||||
token = models.CharField(max_length = 50, unique = True)
|
||||
|
|
58
kfet/static/kfet/css/transfers_form.css
Normal file
58
kfet/static/kfet/css/transfers_form.css
Normal file
|
@ -0,0 +1,58 @@
|
|||
.transfer_formset {
|
||||
background:#FFF;
|
||||
}
|
||||
|
||||
.transfer_formset thead {
|
||||
height:40px;
|
||||
background:#c8102e;
|
||||
color:#fff;
|
||||
font-size:20px;
|
||||
font-weight:bold;
|
||||
text-align:center;
|
||||
}
|
||||
|
||||
.transfer_form {
|
||||
height:50px;
|
||||
}
|
||||
|
||||
.transfer_form td {
|
||||
padding:0 !important;
|
||||
}
|
||||
|
||||
.transfer_form input {
|
||||
border:0;
|
||||
border-radius:0;
|
||||
|
||||
width:100%;
|
||||
height:100%;
|
||||
|
||||
font-family:'Roboto Mono';
|
||||
font-size:25px;
|
||||
font-weight:bold;
|
||||
|
||||
text-align:center;
|
||||
text-transform:uppercase;
|
||||
}
|
||||
|
||||
.transfer_form .from_acc_data, .transfer_form .to_acc_data {
|
||||
width:30%;
|
||||
text-align:center;
|
||||
vertical-align:middle;
|
||||
font-size:20px;
|
||||
}
|
||||
|
||||
.transfer_form .from_acc, .transfer_form .to_acc {
|
||||
width:15%;
|
||||
}
|
||||
|
||||
.transfer_form .from_acc {
|
||||
border-left:1px solid #ddd;
|
||||
}
|
||||
|
||||
.transfer_form .to_acc {
|
||||
border-right:1px solid #ddd;
|
||||
}
|
||||
|
||||
.transfer_form .amount {
|
||||
width:10%;
|
||||
}
|
|
@ -9,21 +9,22 @@ $(document).ready(function() {
|
|||
}
|
||||
});
|
||||
|
||||
// Retrieving csrf token
|
||||
csrftoken = Cookies.get('csrftoken');
|
||||
// Appending csrf token to ajax post requests
|
||||
function csrfSafeMethod(method) {
|
||||
// these HTTP methods do not require CSRF protection
|
||||
return (/^(GET|HEAD|OPTIONS|TRACE)$/.test(method));
|
||||
}
|
||||
$.ajaxSetup({
|
||||
beforeSend: function(xhr, settings) {
|
||||
if (!csrfSafeMethod(settings.type) && !this.crossDomain) {
|
||||
xhr.setRequestHeader("X-CSRFToken", csrftoken);
|
||||
}
|
||||
if (typeof Cookies !== 'undefined') {
|
||||
// Retrieving csrf token
|
||||
csrftoken = Cookies.get('csrftoken');
|
||||
// Appending csrf token to ajax post requests
|
||||
function csrfSafeMethod(method) {
|
||||
// these HTTP methods do not require CSRF protection
|
||||
return (/^(GET|HEAD|OPTIONS|TRACE)$/.test(method));
|
||||
}
|
||||
});
|
||||
|
||||
$.ajaxSetup({
|
||||
beforeSend: function(xhr, settings) {
|
||||
if (!csrfSafeMethod(settings.type) && !this.crossDomain) {
|
||||
xhr.setRequestHeader("X-CSRFToken", csrftoken);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
function dateUTCToParis(date) {
|
||||
|
@ -40,3 +41,68 @@ function amountToUKF(amount, is_cof=false) {
|
|||
var coef_cof = is_cof ? 1 + settings['subvention_cof'] / 100 : 1;
|
||||
return Math.round(amount * coef_cof * 10);
|
||||
}
|
||||
|
||||
function isValidTrigramme(trigramme) {
|
||||
var pattern = /^[^a-z]{3}$/;
|
||||
return trigramme.match(pattern);
|
||||
}
|
||||
|
||||
function getErrorsHtml(data) {
|
||||
var content = '';
|
||||
if ('operation_group' in data['errors']) {
|
||||
content += 'Général';
|
||||
content += '<ul>';
|
||||
if (data['errors']['operation_group'].indexOf('on_acc') != -1)
|
||||
content += '<li>Pas de compte sélectionné</li>';
|
||||
if (data['errors']['operation_group'].indexOf('checkout') != -1)
|
||||
content += '<li>Pas de caisse sélectionnée</li>';
|
||||
content += '</ul>';
|
||||
}
|
||||
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'])
|
||||
content += '<a class="btn btn-primary" href="/k-fet/accounts/'+account_data['trigramme']+'/edit" target="_blank">Autorisation de négatif requise</a>';
|
||||
if ('addcost' in data['errors']) {
|
||||
content += '<ul>';
|
||||
if (data['errors']['addcost'].indexOf('__all__') != -1)
|
||||
content += '<li>Compte invalide</li>';
|
||||
if (data['errors']['addcost'].indexOf('amount') != -1)
|
||||
content += '<li>Montant invalide</li>';
|
||||
content += '</ul>';
|
||||
}
|
||||
return content;
|
||||
}
|
||||
|
||||
function requestAuth(data, callback, focus_next = null) {
|
||||
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();
|
||||
});
|
||||
},
|
||||
onClose: function() {
|
||||
if (focus_next)
|
||||
this._lastFocused = focus_next;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
|
|
@ -141,9 +141,8 @@ $(document).ready(function() {
|
|||
|
||||
// Initializing
|
||||
var account_container = $('#account');
|
||||
var triInput = $('#id_trigramme')
|
||||
var triPattern = /^[^a-z]{3}$/
|
||||
var account_data = {}
|
||||
var triInput = $('#id_trigramme');
|
||||
var account_data = {};
|
||||
var account_data_default = {
|
||||
'id' : 0,
|
||||
'name' : '',
|
||||
|
@ -155,7 +154,7 @@ $(document).ready(function() {
|
|||
'is_frozen' : false,
|
||||
'departement': '',
|
||||
'nickname' : '',
|
||||
}
|
||||
};
|
||||
|
||||
// Display data
|
||||
function displayAccountData() {
|
||||
|
@ -212,7 +211,7 @@ $(document).ready(function() {
|
|||
function retrieveAccountData(tri) {
|
||||
$.ajax({
|
||||
dataType: "json",
|
||||
url : "{% url 'kfet.kpsul.account_data' %}",
|
||||
url : "{% url 'kfet.account.read.json' %}",
|
||||
method : "POST",
|
||||
data : { trigramme: tri },
|
||||
})
|
||||
|
@ -229,7 +228,7 @@ $(document).ready(function() {
|
|||
triInput.on('input', function() {
|
||||
var tri = triInput.val().toUpperCase();
|
||||
// Checking if tri is valid to avoid sending requests
|
||||
if (tri.match(triPattern)) {
|
||||
if (isValidTrigramme(tri)) {
|
||||
retrieveAccountData(tri);
|
||||
} else {
|
||||
resetAccountData();
|
||||
|
@ -318,31 +317,6 @@ $(document).ready(function() {
|
|||
// Auth
|
||||
// -----
|
||||
|
||||
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();
|
||||
});
|
||||
},
|
||||
onClose: function() { this._lastFocused = articleSelect; }
|
||||
});
|
||||
}
|
||||
|
||||
function askComment(callback) {
|
||||
var comment = $('#id_comment').val();
|
||||
$.confirm({
|
||||
|
@ -374,38 +348,7 @@ $(document).ready(function() {
|
|||
// -----
|
||||
// Errors ajax
|
||||
// -----
|
||||
|
||||
function getErrorsHtml(data) {
|
||||
var content = '';
|
||||
if ('operation_group' in data['errors']) {
|
||||
content += 'Général';
|
||||
content += '<ul>';
|
||||
if (data['errors']['operation_group'].indexOf('on_acc') != -1)
|
||||
content += '<li>Pas de compte sélectionné</li>';
|
||||
if (data['errors']['operation_group'].indexOf('checkout') != -1)
|
||||
content += '<li>Pas de caisse sélectionnée</li>';
|
||||
content += '</ul>';
|
||||
}
|
||||
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'])
|
||||
content += '<a class="btn btn-primary" href="/k-fet/accounts/'+account_data['trigramme']+'/edit" target="_blank">Autorisation de négatif requise</a>';
|
||||
if ('addcost' in data['errors']) {
|
||||
content += '<ul>';
|
||||
if (data['errors']['addcost'].indexOf('__all__') != -1)
|
||||
content += '<li>Compte invalide</li>';
|
||||
if (data['errors']['addcost'].indexOf('amount') != -1)
|
||||
content += '<li>Montant invalide</li>';
|
||||
content += '</ul>';
|
||||
}
|
||||
return content;
|
||||
}
|
||||
|
||||
x
|
||||
function displayErrors(html) {
|
||||
$.alert({
|
||||
title: 'Erreurs',
|
||||
|
@ -445,7 +388,7 @@ $(document).ready(function() {
|
|||
var data = $xhr.responseJSON;
|
||||
switch ($xhr.status) {
|
||||
case 403:
|
||||
requestAuth(data, performOperations);
|
||||
requestAuth(data, performOperations, articleSelect);
|
||||
break;
|
||||
case 400:
|
||||
if ('need_comment' in data['errors']) {
|
||||
|
@ -493,7 +436,7 @@ $(document).ready(function() {
|
|||
case 403:
|
||||
requestAuth(data, function(password) {
|
||||
cancelOperations(opes_array, password);
|
||||
});
|
||||
}, triInput);
|
||||
break;
|
||||
case 400:
|
||||
displayErrors(getErrorsHtml(data));
|
||||
|
@ -1023,7 +966,7 @@ $(document).ready(function() {
|
|||
case 403:
|
||||
requestAuth(data, function(password) {
|
||||
sendAddcost(trigramme, amount, password);
|
||||
});
|
||||
}, triInput);
|
||||
break;
|
||||
case 400:
|
||||
askAddcost(getErrorsHtml(data));
|
||||
|
|
16
kfet/templates/kfet/transfers.html
Normal file
16
kfet/templates/kfet/transfers.html
Normal file
|
@ -0,0 +1,16 @@
|
|||
{% extends 'kfet/base.html' %}
|
||||
|
||||
{% block title %}Transferts{% endblock %}
|
||||
{% block content-header-title %}Transferts{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
|
||||
<div class="row">
|
||||
<form action="" method="post">
|
||||
{% csrf_token %}
|
||||
{{ form }}
|
||||
<input type="submit" value="Enregistrer">
|
||||
</form>
|
||||
</div>
|
||||
|
||||
{% endblock %}
|
122
kfet/templates/kfet/transfers_create.html
Normal file
122
kfet/templates/kfet/transfers_create.html
Normal file
|
@ -0,0 +1,122 @@
|
|||
{% extends 'kfet/base.html' %}
|
||||
{% load staticfiles %}
|
||||
|
||||
{% block extra_head %}
|
||||
<link rel="stylesheet" type="text/css" href="{% static 'kfet/css/transfers_form.css' %}">
|
||||
<script type="text/javascript" src="{% static 'kfet/js/js.cookie.js' %}"></script>
|
||||
{% endblock %}
|
||||
|
||||
{% block title %}Nouveaux transferts{% endblock %}
|
||||
{% block content-header-title %}Nouveaux transferts{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
|
||||
{% csrf_token %}
|
||||
|
||||
<form id="transfers_form">
|
||||
<table class="transfer_formset table">
|
||||
<thead>
|
||||
<tr>
|
||||
<td></td>
|
||||
<td>De</td>
|
||||
<td><span class="glyphicon glyphicon-euro"></span></td>
|
||||
<td>Vers</td>
|
||||
<td></td>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{% for form in transfer_formset %}
|
||||
<tr class="transfer_form" id="{{ form.prefix }}">
|
||||
<td class="from_acc_data"></td>
|
||||
<td class="from_acc">
|
||||
<input type="text" name="from_acc" class="input_from_acc" autocomplete="off" spellcheck="false">
|
||||
{{ form.from_acc }}
|
||||
</td>
|
||||
<td class="amount">{{ form.amount }}</td>
|
||||
<td class="to_acc">
|
||||
<input type="text" name="to_acc" class="input_to_acc" autocomplete="off" spellcheck="false">
|
||||
{{ form.to_acc }}
|
||||
</td>
|
||||
<td class="to_acc_data"></td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
</table>
|
||||
<div>
|
||||
<label for="comment">Commentaire:</label>
|
||||
<input type="text" name="comment" id="comment">
|
||||
{{ transfer_formset.management_form }}
|
||||
<button type="submit" id="submit" class="btn btn-primary btn-lg">Enregistrer</button>
|
||||
</div>
|
||||
</form>
|
||||
|
||||
<script type="text/javascript">
|
||||
$(document).ready(function () {
|
||||
function getAccountData(trigramme, callback = function() {}) {
|
||||
$.ajax({
|
||||
dataType: "json",
|
||||
url : "{% url 'kfet.account.read.json' %}",
|
||||
method : "POST",
|
||||
data : { trigramme: trigramme },
|
||||
success : callback,
|
||||
});
|
||||
}
|
||||
|
||||
function updateAccountData(trigramme, $input) {
|
||||
var $form = $input.closest('.transfer_form');
|
||||
if ($input.attr('name') == 'from_acc') {
|
||||
var $data = $form.find('.from_acc_data');
|
||||
var $next = $form.find('.amount input');
|
||||
} else {
|
||||
var $data = $form.find('.to_acc_data');
|
||||
var $next = $form.next('.transfer_form').find('.from_acc input');
|
||||
}
|
||||
var $input_id = $input.next('input');
|
||||
getAccountData(trigramme, function(data) {
|
||||
$input_id.val(data.id);
|
||||
$data.text(data.name);
|
||||
$next.focus();
|
||||
});
|
||||
}
|
||||
|
||||
$('.input_from_acc, .input_to_acc').on('input', function() {
|
||||
var tri = $(this).val().toUpperCase();
|
||||
if (isValidTrigramme(tri)) {
|
||||
updateAccountData(tri, $(this));
|
||||
}
|
||||
});
|
||||
|
||||
$('#transfers_form').on('submit', function(e) {
|
||||
e.preventDefault();
|
||||
performTransfers();
|
||||
});
|
||||
|
||||
function performTransfers(password = '') {
|
||||
var data = $('#transfers_form').serialize();
|
||||
$.ajax({
|
||||
dataType: "json",
|
||||
url : "{% url 'kfet.transfers.perform' %}",
|
||||
method : "POST",
|
||||
data : data,
|
||||
beforeSend: function ($xhr) {
|
||||
$xhr.setRequestHeader("X-CSRFToken", csrftoken);
|
||||
if (password != '')
|
||||
$xhr.setRequestHeader("KFetPassword", password);
|
||||
},
|
||||
})
|
||||
.done(function(data) {
|
||||
window.location.replace("{% url 'kfet.transfers' %}");
|
||||
})
|
||||
.fail(function($xhr) {
|
||||
var data = $xhr.responseJSON;
|
||||
switch ($xhr.status) {
|
||||
case 403:
|
||||
requestAuth(data, performTransfers);
|
||||
break;
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
||||
{% endblock %}
|
22
kfet/urls.py
22
kfet/urls.py
|
@ -117,8 +117,6 @@ urlpatterns = [
|
|||
# -----
|
||||
|
||||
url('^k-psul/$', views.kpsul, name = 'kfet.kpsul'),
|
||||
url('^k-psul/account_data$', views.kpsul_account_data,
|
||||
name = 'kfet.kpsul.account_data'),
|
||||
url('^k-psul/checkout_data$', views.kpsul_checkout_data,
|
||||
name = 'kfet.kpsul.checkout_data'),
|
||||
url('^k-psul/perform_operations$', views.kpsul_perform_operations,
|
||||
|
@ -136,17 +134,31 @@ urlpatterns = [
|
|||
# JSON urls
|
||||
# -----
|
||||
|
||||
url('^history.json$', views.history_json,
|
||||
url(r'^history.json$', views.history_json,
|
||||
name = 'kfet.history.json'),
|
||||
url(r'^accounts/read.json$', views.account_read_json,
|
||||
name = 'kfet.account.read.json'),
|
||||
|
||||
|
||||
# -----
|
||||
# Settings urls
|
||||
# -----
|
||||
|
||||
url('^settings/$',
|
||||
url(r'^settings/$',
|
||||
permission_required('kfet.change_settings')(views.SettingsList.as_view()),
|
||||
name = 'kfet.settings'),
|
||||
url('^settings/(?P<pk>\d+)/edit$',
|
||||
url(r'^settings/(?P<pk>\d+)/edit$',
|
||||
permission_required('kfet.change_settings')(views.SettingsUpdate.as_view()),
|
||||
name = 'kfet.settings.update'),
|
||||
|
||||
# -----
|
||||
# Transfers urls
|
||||
# -----
|
||||
|
||||
url(r'^transfers/$', views.home,
|
||||
name = 'kfet.transfers'),
|
||||
url(r'^transfers/new$', views.transfer_create,
|
||||
name = 'kfet.transfers.create'),
|
||||
url(r'^transfers/perform$', views.perform_transfers,
|
||||
name = 'kfet.transfers.perform'),
|
||||
]
|
||||
|
|
|
@ -600,7 +600,7 @@ def kpsul_get_settings(request):
|
|||
return JsonResponse(data)
|
||||
|
||||
@permission_required('kfet.is_team')
|
||||
def kpsul_account_data(request):
|
||||
def account_read_json(request):
|
||||
trigramme = request.POST.get('trigramme', '')
|
||||
account = get_object_or_404(Account, trigramme=trigramme)
|
||||
data = { 'id': account.pk, 'name': account.name, 'email': account.email,
|
||||
|
@ -931,13 +931,9 @@ def kpsul_cancel_operations(request):
|
|||
return JsonResponse(data)
|
||||
|
||||
# Checking permissions or stop
|
||||
overdraft_duration_max = Settings.OVERDRAFT_DURATION()
|
||||
overdraft_amount_max = Settings.OVERDRAFT_AMOUNT()
|
||||
for account in to_accounts_balances:
|
||||
(perms, stop) = account.perms_to_perform_operation(
|
||||
amount = to_accounts_balances[account],
|
||||
overdraft_duration_max = overdraft_duration_max,
|
||||
overdraft_amount_max = overdraft_amount_max)
|
||||
amount = to_accounts_balances[account])
|
||||
required_perms |= perms
|
||||
stop_all = stop_all or stop
|
||||
|
||||
|
@ -1125,5 +1121,83 @@ class SettingsUpdate(SuccessMessageMixin, UpdateView):
|
|||
form.add_error(None, 'Permission refusée')
|
||||
return self.form_invalid(form)
|
||||
# Creating
|
||||
Settings.empty_cache()
|
||||
return super(SettingsUpdate, self).form_valid(form)
|
||||
|
||||
# -----
|
||||
# Transfer views
|
||||
# -----
|
||||
|
||||
def transfer_create(request):
|
||||
transfer_formset = TransferFormSet(queryset=Transfer.objects.none())
|
||||
return render(request, 'kfet/transfers_create.html',
|
||||
{ 'transfer_formset': transfer_formset })
|
||||
|
||||
def perform_transfers(request):
|
||||
data = { 'errors': {}, 'transfers': [], 'transfergroup': 0 }
|
||||
|
||||
# Checking transfer_formset
|
||||
transfer_formset = TransferFormSet(request.POST)
|
||||
if not transfer_formset.is_valid():
|
||||
return JsonResponse({ 'errors': list(transfer_formset.errors)}, status=400)
|
||||
|
||||
transfers = transfer_formset.save(commit = False)
|
||||
|
||||
# Initializing vars
|
||||
required_perms = set() # Required perms to perform all transfers
|
||||
to_accounts_balances = defaultdict(lambda:0) # For balances of accounts
|
||||
|
||||
for transfer in transfers:
|
||||
to_accounts_balances[transfer.from_acc] -= transfer.amount
|
||||
to_accounts_balances[transfer.to_acc] += transfer.amount
|
||||
|
||||
stop_all = False
|
||||
|
||||
# Checking if ok on all accounts
|
||||
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_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'] = True
|
||||
return JsonResponse(data, status=403)
|
||||
|
||||
with transaction.atomic():
|
||||
# Updating balances accounts
|
||||
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()
|
||||
|
||||
# Creating transfer group
|
||||
transfergroup = TransferGroup()
|
||||
if required_perms:
|
||||
transfergroup.valid_by = request.user.profile.account_kfet
|
||||
transfergroup.save()
|
||||
data['transfergroup'] = transfergroup.pk
|
||||
|
||||
# Saving all transfers with group
|
||||
for transfer in transfers:
|
||||
transfer.group = transfergroup
|
||||
transfer.save()
|
||||
data['transfers'].append(transfer.pk)
|
||||
|
||||
return JsonResponse(data)
|
||||
|
|
Loading…
Reference in a new issue