',
- $.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;
- var capslock = -1; // 1 -> caps on ; 0 -> caps off ; -1 or 2 -> unknown
- this.$content.find('input').on('keypress', function (e) {
- if (e.keyCode == 13)
- that.$confirmButton.click();
+ var content = getErrorsHtml(data["missing_perms"], is_error = false);
+ content += '
';
- var s = String.fromCharCode(e.which);
- if ((s.toUpperCase() === s && s.toLowerCase() !== s && !e.shiftKey) || //caps on, shift off
- (s.toUpperCase() !== s && s.toLowerCase() === s && e.shiftKey)) { //caps on, shift on
- capslock = 1;
- } else if ((s.toLowerCase() === s && s.toUpperCase() !== s && !e.shiftKey) || //caps off, shift off
- (s.toLowerCase() !== s && s.toUpperCase() === s && e.shiftKey)) { //caps off, shift on
- capslock = 0;
- }
- if (capslock == 1)
- $('.capslock .glyphicon').show();
- else if (capslock == 0)
- $('.capslock .glyphicon').hide();
- });
- // Capslock key is not detected by keypress
- this.$content.find('input').on('keydown', function (e) {
- if (e.which == 20) {
- capslock = 1 - capslock;
- }
- if (capslock == 1)
- $('.capslock .glyphicon').show();
- else if (capslock == 0)
- $('.capslock .glyphicon').hide();
- });
- },
- onClose: function () {
- if (focus_next)
- this._lastFocused = focus_next;
- }
+ $.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;
+ var capslock = -1; // 1 -> caps on ; 0 -> caps off ; -1 or 2 -> unknown
+ this.$content.find('input').on('keypress', function (e) {
+ if (e.keyCode == 13)
+ that.$confirmButton.click();
- });
+ var s = String.fromCharCode(e.which);
+ if ((s.toUpperCase() === s && s.toLowerCase() !== s && !e.shiftKey) || //caps on, shift off
+ (s.toUpperCase() !== s && s.toLowerCase() === s && e.shiftKey)) { //caps on, shift on
+ capslock = 1;
+ } else if ((s.toLowerCase() === s && s.toUpperCase() !== s && !e.shiftKey) || //caps off, shift off
+ (s.toLowerCase() !== s && s.toUpperCase() === s && e.shiftKey)) { //caps off, shift on
+ capslock = 0;
+ }
+ if (capslock == 1)
+ $('.capslock .glyphicon').show();
+ else if (capslock == 0)
+ $('.capslock .glyphicon').hide();
+ });
+ // Capslock key is not detected by keypress
+ this.$content.find('input').on('keydown', function (e) {
+ if (e.which == 20) {
+ capslock = 1 - capslock;
+ }
+ if (capslock == 1)
+ $('.capslock .glyphicon').show();
+ else if (capslock == 0)
+ $('.capslock .glyphicon').hide();
+ });
+ },
+ onClose: function () {
+ if (focus_next)
+ this._lastFocused = focus_next;
+ }
+
+ });
}
-function displayErrors(html) {
+function displayErrors(data) {
+ const content = getErrorsHtml(data["errors"], is_error = true);
$.alert({
title: 'Erreurs',
- content: html,
+ content: content,
backgroundDismiss: true,
animation: 'top',
closeAnimation: 'bottom',
diff --git a/kfet/templates/kfet/account_negative.html b/kfet/templates/kfet/account_negative.html
index 9ca9cd99..c2390f6d 100644
--- a/kfet/templates/kfet/account_negative.html
+++ b/kfet/templates/kfet/account_negative.html
@@ -10,26 +10,12 @@
{{ negatives|length }}
compte{{ negatives|length|pluralize }} en négatif
-
- Total: {{ negatives_sum|floatformat:2 }}€
-
-
-
Plafond par défaut
-
- - Montant: {{ kfet_config.overdraft_amount }}€
- - Pendant: {{ kfet_config.overdraft_duration }}
-
+
+ {{ negatives_sum|floatformat:2 }}€
+ de négatif total
-{% if perms.kfet.change_settings %}
-
-{% endif %}
-
{% endblock %}
{% block main %}
@@ -43,8 +29,6 @@
Nom |
Balance |
Début |
-
Découvert autorisé |
-
Jusqu'au |
@@ -60,10 +44,6 @@
{{ neg.start|date:'d/m/Y H:i'}}
|
- {{ neg.authz_overdraft_amount|default_if_none:'' }} |
-
- {{ neg.authz_overdraft_until|date:'d/m/Y H:i' }}
- |
{% endfor %}
diff --git a/kfet/templates/kfet/account_update.html b/kfet/templates/kfet/account_update.html
index 2bab6c1d..65965d83 100644
--- a/kfet/templates/kfet/account_update.html
+++ b/kfet/templates/kfet/account_update.html
@@ -35,23 +35,9 @@ Modification de mes informations
{% include 'kfet/form_snippet.html' with form=frozen_form %}
{% include 'kfet/form_snippet.html' with form=group_form %}
{% include 'kfet/form_snippet.html' with form=pwd_form %}
- {% include 'kfet/form_snippet.html' with form=negative_form %}
- {% if perms.kfet.is_team %}
+
{% include 'kfet/form_authentication_snippet.html' %}
- {% endif %}
{% include 'kfet/form_submit_snippet.html' with value="Mettre à jour" %}
-
-
{% endblock %}
\ No newline at end of file
diff --git a/kfet/templates/kfet/kpsul.html b/kfet/templates/kfet/kpsul.html
index ece98578..8259d694 100644
--- a/kfet/templates/kfet/kpsul.html
+++ b/kfet/templates/kfet/kpsul.html
@@ -376,10 +376,10 @@ $(document).ready(function() {
requestAuth(data, performOperations, articleSelect);
break;
case 400:
- if ('need_comment' in data['errors']) {
+ if ('need_comment' in data) {
askComment(performOperations);
} else {
- displayErrors(getErrorsHtml(data));
+ displayErrors(data);
}
break;
}
@@ -1074,7 +1074,7 @@ $(document).ready(function() {
}, triInput);
break;
case 400:
- askAddcost(getErrorsHtml(data));
+ askAddcost(getErrorsHtml(data["errors"], is_error=true));
break;
}
});
diff --git a/kfet/templates/kfet/left_account.html b/kfet/templates/kfet/left_account.html
index e1673d22..a68845ed 100644
--- a/kfet/templates/kfet/left_account.html
+++ b/kfet/templates/kfet/left_account.html
@@ -54,12 +54,6 @@
{% if account.negative.start %}
Depuis le {{ account.negative.start|date:"d/m/Y à H:i" }}
{% endif %}
-
- Plafond :
- {{ account.negative.authz_overdraft_amount|default:kfet_config.overdraft_amount }} €
- jusqu'au
- {{ account.negative.authz_overdraft_until|default:account.negative.until_default|date:"d/m/Y à H:i" }}
-
{% endif %}
diff --git a/kfet/templates/kfet/transfers_create.html b/kfet/templates/kfet/transfers_create.html
index a4a1a450..fc429d97 100644
--- a/kfet/templates/kfet/transfers_create.html
+++ b/kfet/templates/kfet/transfers_create.html
@@ -72,7 +72,7 @@ $(document).ready(function () {
var $next = $form.next('.transfer_form').find('.from_acc input');
}
var $input_id = $input.next('input');
- if (isValidTrigramme(trigramme)) {
+ if (trigramme.is_valid_trigramme()) {
getAccountData(trigramme, function(data) {
$input_id.val(data.id);
$data.text(data.name);
@@ -122,7 +122,7 @@ $(document).ready(function () {
requestAuth(data, performTransfers);
break;
case 400:
- displayErrors(getErrorsHtml(data));
+ displayErrors(data);
break;
}
});
diff --git a/kfet/tests/test_models.py b/kfet/tests/test_models.py
index 7ce6605c..a534493d 100644
--- a/kfet/tests/test_models.py
+++ b/kfet/tests/test_models.py
@@ -1,10 +1,12 @@
-import datetime
+from datetime import datetime, timedelta, timezone as tz
+from decimal import Decimal
+from unittest import mock
from django.contrib.auth import get_user_model
from django.test import TestCase
from django.utils import timezone
-from kfet.models import Account, Checkout
+from kfet.models import Account, AccountNegative, Checkout
from .utils import create_user
@@ -28,6 +30,56 @@ class AccountTests(TestCase):
with self.assertRaises(Account.DoesNotExist):
Account.objects.get_by_password("bernard")
+ @mock.patch("django.utils.timezone.now")
+ def test_negative_creation(self, mock_now):
+ now = datetime(2005, 7, 15, tzinfo=tz.utc)
+ mock_now.return_value = now
+ self.account.balance = Decimal(-10)
+ self.account.update_negative()
+
+ self.assertTrue(hasattr(self.account, "negative"))
+ self.assertEqual(self.account.negative.start, now)
+
+ @mock.patch("django.utils.timezone.now")
+ def test_negative_no_reset(self, mock_now):
+ now = datetime(2005, 7, 15, tzinfo=tz.utc)
+ mock_now.return_value = now
+
+ self.account.balance = Decimal(-10)
+ AccountNegative.objects.create(
+ account=self.account, start=now - timedelta(minutes=3)
+ )
+ self.account.refresh_from_db()
+
+ self.account.balance = Decimal(5)
+ self.account.update_negative()
+ self.assertTrue(hasattr(self.account, "negative"))
+
+ self.account.balance = Decimal(-10)
+ self.account.update_negative()
+ self.assertEqual(self.account.negative.start, now - timedelta(minutes=3))
+
+ @mock.patch("django.utils.timezone.now")
+ def test_negative_eventually_resets(self, mock_now):
+ now = datetime(2005, 7, 15, tzinfo=tz.utc)
+ mock_now.return_value = now
+
+ self.account.balance = Decimal(-10)
+ AccountNegative.objects.create(
+ account=self.account, start=now - timedelta(minutes=20)
+ )
+ self.account.refresh_from_db()
+ self.account.balance = Decimal(5)
+
+ mock_now.return_value = now - timedelta(minutes=10)
+ self.account.update_negative()
+
+ mock_now.return_value = now
+ self.account.update_negative()
+ self.account.refresh_from_db()
+
+ self.assertFalse(hasattr(self.account, "negative"))
+
class CheckoutTests(TestCase):
def setUp(self):
@@ -39,7 +91,7 @@ class CheckoutTests(TestCase):
self.c = Checkout(
created_by=self.u_acc,
valid_from=self.now,
- valid_to=self.now + datetime.timedelta(days=1),
+ valid_to=self.now + timedelta(days=1),
)
def test_initial_statement(self):
diff --git a/kfet/tests/test_views.py b/kfet/tests/test_views.py
index c4d31ae2..7a7eddcb 100644
--- a/kfet/tests/test_views.py
+++ b/kfet/tests/test_views.py
@@ -15,7 +15,6 @@ from ..auth.utils import hash_password
from ..config import kfet_config
from ..models import (
Account,
- AccountNegative,
Article,
ArticleCategory,
Checkout,
@@ -1856,7 +1855,10 @@ class KPsulPerformOperationsViewTests(ViewTestCaseMixin, TestCase):
self.assertEqual(resp.status_code, 400)
json_data = json.loads(resp.content.decode("utf-8"))
- self.assertEqual(json_data["errors"]["operation_group"], ["on_acc"])
+ self.assertCountEqual(
+ [e["code"] for e in json_data["errors"]],
+ ["invalid_on_acc", "invalid_formset"],
+ )
def test_group_on_acc_expects_comment(self):
user_add_perms(self.users["team"], ["kfet.perform_commented_operations"])
@@ -1899,7 +1901,7 @@ class KPsulPerformOperationsViewTests(ViewTestCaseMixin, TestCase):
self.assertEqual(resp.status_code, 400)
json_data = json.loads(resp.content.decode("utf-8"))
- self.assertEqual(json_data["errors"]["need_comment"], True)
+ self.assertEqual(json_data["need_comment"], True)
def test_invalid_group_on_acc_needs_comment_requires_perm(self):
self.account.trigramme = "#13"
@@ -1922,8 +1924,8 @@ class KPsulPerformOperationsViewTests(ViewTestCaseMixin, TestCase):
self.assertEqual(resp.status_code, 403)
json_data = json.loads(resp.content.decode("utf-8"))
self.assertEqual(
- json_data["errors"]["missing_perms"],
- ["[kfet] Enregistrer des commandes avec commentaires"],
+ json_data["missing_perms"],
+ ["Enregistrer des commandes avec commentaires"],
)
def test_error_on_acc_frozen(self):
@@ -1945,7 +1947,7 @@ class KPsulPerformOperationsViewTests(ViewTestCaseMixin, TestCase):
self.assertEqual(resp.status_code, 400)
json_data = json.loads(resp.content.decode("utf-8"))
- self.assertEqual(json_data["errors"]["frozen"], [self.account.trigramme])
+ self.assertEqual([e["code"] for e in json_data["errors"]], ["frozen_acc"])
def test_invalid_group_checkout(self):
self.checkout.valid_from -= timedelta(days=300)
@@ -1957,7 +1959,10 @@ class KPsulPerformOperationsViewTests(ViewTestCaseMixin, TestCase):
self.assertEqual(resp.status_code, 400)
json_data = json.loads(resp.content.decode("utf-8"))
- self.assertEqual(json_data["errors"]["operation_group"], ["checkout"])
+ self.assertCountEqual(
+ [e["code"] for e in json_data["errors"]],
+ ["invalid_checkout", "invalid_formset"],
+ )
def test_invalid_group_expects_one_operation(self):
data = dict(self.base_post_data)
@@ -1965,7 +1970,10 @@ class KPsulPerformOperationsViewTests(ViewTestCaseMixin, TestCase):
self.assertEqual(resp.status_code, 400)
json_data = json.loads(resp.content.decode("utf-8"))
- self.assertEqual(json_data["errors"]["operations"], [])
+ self.assertCountEqual(
+ [e["code"] for e in json_data["errors"]],
+ ["invalid_formset"],
+ )
def test_purchase_with_user_is_nof_cof(self):
self.account.cofprofile.is_cof = False
@@ -2023,12 +2031,7 @@ class KPsulPerformOperationsViewTests(ViewTestCaseMixin, TestCase):
# Check response content
self.assertDictEqual(
json_data,
- {
- "operationgroup": operation_group.pk,
- "operations": [operation.pk],
- "warnings": {},
- "errors": {},
- },
+ {"errors": []},
)
# Check object updates
@@ -2179,9 +2182,9 @@ class KPsulPerformOperationsViewTests(ViewTestCaseMixin, TestCase):
self.assertEqual(resp.status_code, 400)
json_data = json.loads(resp.content.decode("utf-8"))
- self.assertEqual(
- json_data["errors"]["operations"],
- [{"__all__": ["Un achat nécessite un article et une quantité"]}],
+ self.assertCountEqual(
+ [e["code"] for e in json_data["errors"]],
+ ["invalid_formset"],
)
def test_invalid_purchase_expects_article_nb(self):
@@ -2199,9 +2202,9 @@ class KPsulPerformOperationsViewTests(ViewTestCaseMixin, TestCase):
self.assertEqual(resp.status_code, 400)
json_data = json.loads(resp.content.decode("utf-8"))
- self.assertEqual(
- json_data["errors"]["operations"],
- [{"__all__": ["Un achat nécessite un article et une quantité"]}],
+ self.assertCountEqual(
+ [e["code"] for e in json_data["errors"]],
+ ["invalid_formset"],
)
def test_invalid_purchase_expects_article_nb_greater_than_1(self):
@@ -2219,16 +2222,9 @@ class KPsulPerformOperationsViewTests(ViewTestCaseMixin, TestCase):
self.assertEqual(resp.status_code, 400)
json_data = json.loads(resp.content.decode("utf-8"))
- self.assertEqual(
- json_data["errors"]["operations"],
- [
- {
- "__all__": ["Un achat nécessite un article et une quantité"],
- "article_nb": [
- "Assurez-vous que cette valeur est supérieure ou " "égale à 1."
- ],
- }
- ],
+ self.assertCountEqual(
+ [e["code"] for e in json_data["errors"]],
+ ["invalid_formset"],
)
def test_invalid_operation_not_purchase_with_cash(self):
@@ -2247,7 +2243,10 @@ class KPsulPerformOperationsViewTests(ViewTestCaseMixin, TestCase):
self.assertEqual(resp.status_code, 400)
json_data = json.loads(resp.content.decode("utf-8"))
- self.assertEqual(json_data["errors"]["account"], "LIQ")
+ self.assertCountEqual(
+ [e["code"] for e in json_data["errors"]],
+ ["invalid_liq"],
+ )
def test_deposit(self):
user_add_perms(self.users["team"], ["kfet.perform_deposit"])
@@ -2300,12 +2299,7 @@ class KPsulPerformOperationsViewTests(ViewTestCaseMixin, TestCase):
self.assertDictEqual(
json_data,
- {
- "operationgroup": operation_group.pk,
- "operations": [operation.pk],
- "warnings": {},
- "errors": {},
- },
+ {"errors": []},
)
self.account.refresh_from_db()
@@ -2364,8 +2358,9 @@ class KPsulPerformOperationsViewTests(ViewTestCaseMixin, TestCase):
self.assertEqual(resp.status_code, 400)
json_data = json.loads(resp.content.decode("utf-8"))
- self.assertEqual(
- json_data["errors"]["operations"], [{"__all__": ["Bad request"]}]
+ self.assertCountEqual(
+ [e["code"] for e in json_data["errors"]],
+ ["invalid_formset"],
)
def test_invalid_deposit_too_many_params(self):
@@ -2383,8 +2378,9 @@ class KPsulPerformOperationsViewTests(ViewTestCaseMixin, TestCase):
self.assertEqual(resp.status_code, 400)
json_data = json.loads(resp.content.decode("utf-8"))
- self.assertEqual(
- json_data["errors"]["operations"], [{"__all__": ["Bad request"]}]
+ self.assertCountEqual(
+ [e["code"] for e in json_data["errors"]],
+ ["invalid_formset"],
)
def test_invalid_deposit_expects_positive_amount(self):
@@ -2402,8 +2398,9 @@ class KPsulPerformOperationsViewTests(ViewTestCaseMixin, TestCase):
self.assertEqual(resp.status_code, 400)
json_data = json.loads(resp.content.decode("utf-8"))
- self.assertEqual(
- json_data["errors"]["operations"], [{"__all__": ["Charge non positive"]}]
+ self.assertCountEqual(
+ [e["code"] for e in json_data["errors"]],
+ ["invalid_formset"],
)
def test_invalid_deposit_requires_perm(self):
@@ -2421,9 +2418,7 @@ class KPsulPerformOperationsViewTests(ViewTestCaseMixin, TestCase):
self.assertEqual(resp.status_code, 403)
json_data = json.loads(resp.content.decode("utf-8"))
- self.assertEqual(
- json_data["errors"]["missing_perms"], ["[kfet] Effectuer une charge"]
- )
+ self.assertEqual(json_data["missing_perms"], ["Effectuer une charge"])
def test_withdraw(self):
data = dict(
@@ -2475,12 +2470,7 @@ class KPsulPerformOperationsViewTests(ViewTestCaseMixin, TestCase):
self.assertDictEqual(
json_data,
- {
- "operationgroup": operation_group.pk,
- "operations": [operation.pk],
- "warnings": {},
- "errors": {},
- },
+ {"errors": []},
)
self.account.refresh_from_db()
@@ -2539,8 +2529,9 @@ class KPsulPerformOperationsViewTests(ViewTestCaseMixin, TestCase):
self.assertEqual(resp.status_code, 400)
json_data = json.loads(resp.content.decode("utf-8"))
- self.assertEqual(
- json_data["errors"]["operations"], [{"__all__": ["Bad request"]}]
+ self.assertCountEqual(
+ [e["code"] for e in json_data["errors"]],
+ ["invalid_formset"],
)
def test_invalid_withdraw_too_many_params(self):
@@ -2558,8 +2549,9 @@ class KPsulPerformOperationsViewTests(ViewTestCaseMixin, TestCase):
self.assertEqual(resp.status_code, 400)
json_data = json.loads(resp.content.decode("utf-8"))
- self.assertEqual(
- json_data["errors"]["operations"], [{"__all__": ["Bad request"]}]
+ self.assertCountEqual(
+ [e["code"] for e in json_data["errors"]],
+ ["invalid_formset"],
)
def test_invalid_withdraw_expects_negative_amount(self):
@@ -2577,8 +2569,9 @@ class KPsulPerformOperationsViewTests(ViewTestCaseMixin, TestCase):
self.assertEqual(resp.status_code, 400)
json_data = json.loads(resp.content.decode("utf-8"))
- self.assertEqual(
- json_data["errors"]["operations"], [{"__all__": ["Retrait non négatif"]}]
+ self.assertCountEqual(
+ [e["code"] for e in json_data["errors"]],
+ ["invalid_formset"],
)
def test_edit(self):
@@ -2634,12 +2627,7 @@ class KPsulPerformOperationsViewTests(ViewTestCaseMixin, TestCase):
self.assertDictEqual(
json_data,
- {
- "operationgroup": operation_group.pk,
- "operations": [operation.pk],
- "warnings": {},
- "errors": {},
- },
+ {"errors": []},
)
self.account.refresh_from_db()
@@ -2700,8 +2688,8 @@ class KPsulPerformOperationsViewTests(ViewTestCaseMixin, TestCase):
self.assertEqual(resp.status_code, 403)
json_data = json.loads(resp.content.decode("utf-8"))
self.assertEqual(
- json_data["errors"]["missing_perms"],
- ["[kfet] Modifier la balance d'un compte"],
+ json_data["missing_perms"],
+ ["Modifier la balance d'un compte"],
)
def test_invalid_edit_expects_comment(self):
@@ -2721,7 +2709,7 @@ class KPsulPerformOperationsViewTests(ViewTestCaseMixin, TestCase):
self.assertEqual(resp.status_code, 400)
json_data = json.loads(resp.content.decode("utf-8"))
- self.assertEqual(json_data["errors"]["need_comment"], True)
+ self.assertEqual(json_data["need_comment"], True)
def _setup_addcost(self):
self.register_user("addcost", create_user("addcost", "ADD"))
@@ -3008,62 +2996,10 @@ class KPsulPerformOperationsViewTests(ViewTestCaseMixin, TestCase):
self.assertEqual(resp.status_code, 403)
json_data = json.loads(resp.content.decode("utf-8"))
self.assertEqual(
- json_data["errors"],
- {"missing_perms": ["[kfet] Enregistrer des commandes en négatif"]},
+ json_data["missing_perms"],
+ ["Enregistrer des commandes en négatif"],
)
- def test_invalid_negative_exceeds_allowed_duration_from_config(self):
- user_add_perms(self.users["team"], ["kfet.perform_negative_operations"])
- kfet_config.set(overdraft_duration=timedelta(days=5))
- self.account.balance = Decimal("1.00")
- self.account.save()
- self.account.negative = AccountNegative.objects.create(
- account=self.account, start=timezone.now() - timedelta(days=5, minutes=1)
- )
-
- data = dict(
- self.base_post_data,
- **{
- "form-TOTAL_FORMS": "1",
- "form-0-type": "purchase",
- "form-0-amount": "",
- "form-0-article": str(self.article.pk),
- "form-0-article_nb": "2",
- }
- )
- resp = self.client.post(self.url, data)
-
- self.assertEqual(resp.status_code, 403)
- json_data = json.loads(resp.content.decode("utf-8"))
- self.assertEqual(json_data["errors"], {"negative": ["000"]})
-
- def test_invalid_negative_exceeds_allowed_duration_from_account(self):
- user_add_perms(self.users["team"], ["kfet.perform_negative_operations"])
- kfet_config.set(overdraft_duration=timedelta(days=5))
- self.account.balance = Decimal("1.00")
- self.account.save()
- self.account.negative = AccountNegative.objects.create(
- account=self.account,
- start=timezone.now() - timedelta(days=3),
- authz_overdraft_until=timezone.now() - timedelta(seconds=1),
- )
-
- data = dict(
- self.base_post_data,
- **{
- "form-TOTAL_FORMS": "1",
- "form-0-type": "purchase",
- "form-0-amount": "",
- "form-0-article": str(self.article.pk),
- "form-0-article_nb": "2",
- }
- )
- resp = self.client.post(self.url, data)
-
- self.assertEqual(resp.status_code, 403)
- json_data = json.loads(resp.content.decode("utf-8"))
- self.assertEqual(json_data["errors"], {"negative": ["000"]})
-
def test_invalid_negative_exceeds_amount_allowed_from_config(self):
user_add_perms(self.users["team"], ["kfet.perform_negative_operations"])
kfet_config.set(overdraft_amount=Decimal("-1.00"))
@@ -3083,38 +3019,13 @@ class KPsulPerformOperationsViewTests(ViewTestCaseMixin, TestCase):
)
resp = self.client.post(self.url, data)
- self.assertEqual(resp.status_code, 403)
+ self.assertEqual(resp.status_code, 400)
json_data = json.loads(resp.content.decode("utf-8"))
- self.assertEqual(json_data["errors"], {"negative": ["000"]})
-
- def test_invalid_negative_exceeds_amount_allowed_from_account(self):
- user_add_perms(self.users["team"], ["kfet.perform_negative_operations"])
- kfet_config.set(overdraft_amount=Decimal("10.00"))
- self.account.balance = Decimal("1.00")
- self.account.save()
- self.account.update_negative()
- self.account.negative = AccountNegative.objects.create(
- account=self.account,
- start=timezone.now() - timedelta(days=3),
- authz_overdraft_amount=Decimal("1.00"),
+ self.assertCountEqual(
+ [e["code"] for e in json_data["errors"]],
+ ["negative"],
)
- data = dict(
- self.base_post_data,
- **{
- "form-TOTAL_FORMS": "1",
- "form-0-type": "purchase",
- "form-0-amount": "",
- "form-0-article": str(self.article.pk),
- "form-0-article_nb": "2",
- }
- )
- resp = self.client.post(self.url, data)
-
- self.assertEqual(resp.status_code, 403)
- json_data = json.loads(resp.content.decode("utf-8"))
- self.assertEqual(json_data["errors"], {"negative": ["000"]})
-
def test_multi_0(self):
article2 = Article.objects.create(
name="Article 2",
@@ -3198,12 +3109,7 @@ class KPsulPerformOperationsViewTests(ViewTestCaseMixin, TestCase):
# Check response content
self.assertDictEqual(
json_data,
- {
- "operationgroup": operation_group.pk,
- "operations": [operation_list[0].pk, operation_list[1].pk],
- "warnings": {},
- "errors": {},
- },
+ {"errors": []},
)
# Check object updates
@@ -3342,7 +3248,10 @@ class KPsulCancelOperationsViewTests(ViewTestCaseMixin, TestCase):
self.assertEqual(resp.status_code, 400)
json_data = json.loads(resp.content.decode("utf-8"))
- self.assertEqual(json_data["errors"], {})
+ self.assertCountEqual(
+ [e["code"] for e in json_data["errors"]],
+ ["invalid_request"],
+ )
def test_invalid_operation_not_exist(self):
data = {"operations[]": ["1000"]}
@@ -3350,7 +3259,10 @@ class KPsulCancelOperationsViewTests(ViewTestCaseMixin, TestCase):
self.assertEqual(resp.status_code, 400)
json_data = json.loads(resp.content.decode("utf-8"))
- self.assertEqual(json_data["errors"], {"opes_notexisting": [1000]})
+ self.assertCountEqual(
+ [e["code"] for e in json_data["errors"]],
+ ["cancel_missing"],
+ )
@mock.patch("django.utils.timezone.now")
def test_purchase(self, now_mock):
@@ -3414,7 +3326,7 @@ class KPsulCancelOperationsViewTests(ViewTestCaseMixin, TestCase):
"canceled_by__trigramme": None,
}
],
- "errors": {},
+ "errors": [],
"warnings": {},
"opegroups_to_update": [
{
@@ -3602,7 +3514,7 @@ class KPsulCancelOperationsViewTests(ViewTestCaseMixin, TestCase):
"canceled_by__trigramme": None,
}
],
- "errors": {},
+ "errors": [],
"warnings": {},
"opegroups_to_update": [
{
@@ -3689,7 +3601,7 @@ class KPsulCancelOperationsViewTests(ViewTestCaseMixin, TestCase):
"canceled_by__trigramme": None,
}
],
- "errors": {},
+ "errors": [],
"warnings": {},
"opegroups_to_update": [
{
@@ -3776,7 +3688,7 @@ class KPsulCancelOperationsViewTests(ViewTestCaseMixin, TestCase):
"canceled_by__trigramme": None,
}
],
- "errors": {},
+ "errors": [],
"warnings": {},
"opegroups_to_update": [
{
@@ -3839,8 +3751,8 @@ class KPsulCancelOperationsViewTests(ViewTestCaseMixin, TestCase):
self.assertEqual(resp.status_code, 403)
json_data = json.loads(resp.content.decode("utf-8"))
self.assertEqual(
- json_data["errors"],
- {"missing_perms": ["[kfet] Annuler des commandes non récentes"]},
+ json_data["missing_perms"],
+ ["Annuler des commandes non récentes"],
)
def test_already_canceled(self):
@@ -3964,9 +3876,12 @@ class KPsulCancelOperationsViewTests(ViewTestCaseMixin, TestCase):
data = {"operations[]": [str(operation.pk)]}
resp = self.client.post(self.url, data)
- self.assertEqual(resp.status_code, 403)
+ self.assertEqual(resp.status_code, 400)
json_data = json.loads(resp.content.decode("utf-8"))
- self.assertEqual(json_data["errors"], {"negative": [self.account.trigramme]})
+ self.assertCountEqual(
+ [e["code"] for e in json_data["errors"]],
+ ["negative"],
+ )
def test_invalid_negative_requires_perms(self):
kfet_config.set(overdraft_amount=Decimal("40.00"))
@@ -3985,8 +3900,8 @@ class KPsulCancelOperationsViewTests(ViewTestCaseMixin, TestCase):
self.assertEqual(resp.status_code, 403)
json_data = json.loads(resp.content.decode("utf-8"))
self.assertEqual(
- json_data["errors"],
- {"missing_perms": ["[kfet] Enregistrer des commandes en négatif"]},
+ json_data["missing_perms"],
+ ["Enregistrer des commandes en négatif"],
)
def test_partial_0(self):
@@ -4036,7 +3951,7 @@ class KPsulCancelOperationsViewTests(ViewTestCaseMixin, TestCase):
"canceled_by__trigramme": None,
},
],
- "errors": {},
+ "errors": [],
"warnings": {"already_canceled": [operation3.pk]},
"opegroups_to_update": [
{
diff --git a/kfet/views.py b/kfet/views.py
index 83bf380a..0d9f9544 100644
--- a/kfet/views.py
+++ b/kfet/views.py
@@ -15,7 +15,7 @@ from django.contrib.messages.views import SuccessMessageMixin
from django.core.exceptions import SuspiciousOperation, ValidationError
from django.db import transaction
from django.db.models import Count, F, Max, OuterRef, Prefetch, Q, Subquery, Sum
-from django.forms import formset_factory
+from django.forms import ValidationError, formset_factory
from django.http import (
Http404,
HttpResponseBadRequest,
@@ -39,7 +39,6 @@ from kfet.decorators import teamkfet_required
from kfet.forms import (
AccountForm,
AccountFrozenForm,
- AccountNegativeForm,
AccountNoTriForm,
AccountPwdForm,
AccountStatForm,
@@ -355,11 +354,6 @@ def account_update(request, trigramme):
frozen_form = AccountFrozenForm(request.POST, instance=account)
pwd_form = AccountPwdForm()
- if hasattr(account, "negative"):
- negative_form = AccountNegativeForm(instance=account.negative)
- else:
- negative_form = None
-
if request.method == "POST":
self_update = request.user == account.user
account_form = AccountForm(request.POST, instance=account)
@@ -381,14 +375,6 @@ def account_update(request, trigramme):
elif group_form.has_changed():
warnings.append("statut d'équipe")
- if hasattr(account, "negative"):
- negative_form = AccountNegativeForm(request.POST, instance=account.negative)
-
- if request.user.has_perm("kfet.change_accountnegative"):
- forms.append(negative_form)
- elif negative_form.has_changed():
- warnings.append("négatifs")
-
# Il ne faut pas valider `pwd_form` si elle est inchangée
if pwd_form.has_changed():
if self_update or request.user.has_perm("kfet.change_account_password"):
@@ -437,7 +423,6 @@ def account_update(request, trigramme):
"account_form": account_form,
"frozen_form": frozen_form,
"group_form": group_form,
- "negative_form": negative_form,
"pwd_form": pwd_form,
},
)
@@ -482,9 +467,11 @@ class AccountDelete(PermissionRequiredMixin, DeleteView):
class AccountNegativeList(ListView):
- queryset = AccountNegative.objects.select_related(
- "account", "account__cofprofile__user"
- ).exclude(account__trigramme="#13")
+ queryset = (
+ AccountNegative.objects.select_related("account", "account__cofprofile__user")
+ .filter(account__balance__lt=0)
+ .exclude(account__trigramme="#13")
+ )
template_name = "kfet/account_negative.html"
context_object_name = "negatives"
@@ -977,15 +964,18 @@ def kpsul_checkout_data(request):
@kfet_password_auth
def kpsul_update_addcost(request):
addcost_form = AddcostForm(request.POST)
+ data = {"errors": []}
if not addcost_form.is_valid():
- data = {"errors": {"addcost": list(addcost_form.errors)}}
+ for (field, errors) in addcost_form.errors.items():
+ for error in errors:
+ data["errors"].append({"code": f"invalid_{field}", "message": error})
+
return JsonResponse(data, status=400)
+
required_perms = ["kfet.manage_addcosts"]
if not request.user.has_perms(required_perms):
- data = {
- "errors": {"missing_perms": get_missing_perms(required_perms, request.user)}
- }
+ data["missing_perms"] = get_missing_perms(required_perms, request.user)
return JsonResponse(data, status=403)
trigramme = addcost_form.cleaned_data["trigramme"]
@@ -1000,14 +990,13 @@ def kpsul_update_addcost(request):
def get_missing_perms(required_perms: List[str], user: User) -> List[str]:
- def get_perm_description(app_label: str, codename: str) -> str:
- name = Permission.objects.values_list("name", flat=True).get(
+ def get_perm_name(app_label: str, codename: str) -> str:
+ return Permission.objects.values_list("name", flat=True).get(
codename=codename, content_type__app_label=app_label
)
- return "[{}] {}".format(app_label, name)
missing_perms = [
- get_perm_description(*perm.split("."))
+ get_perm_name(*perm.split("."))
for perm in required_perms
if not user.has_perm(perm)
]
@@ -1019,17 +1008,31 @@ def get_missing_perms(required_perms: List[str], user: User) -> List[str]:
@kfet_password_auth
def kpsul_perform_operations(request):
# Initializing response data
- data = {"operationgroup": 0, "operations": [], "warnings": {}, "errors": {}}
+ data = {"errors": []}
# Checking operationgroup
operationgroup_form = KPsulOperationGroupForm(request.POST)
if not operationgroup_form.is_valid():
- data["errors"]["operation_group"] = list(operationgroup_form.errors)
+ for field in operationgroup_form.errors:
+ verbose_field, feminin = (
+ ("compte", "") if field == "on_acc" else ("caisse", "e")
+ )
+ data["errors"].append(
+ {
+ "code": f"invalid_{field}",
+ "message": f"Pas de {verbose_field} sélectionné{feminin}",
+ }
+ )
# Checking operation_formset
operation_formset = KPsulOperationFormSet(request.POST)
if not operation_formset.is_valid():
- data["errors"]["operations"] = list(operation_formset.errors)
+ data["errors"].append(
+ {
+ "code": "invalid_formset",
+ "message": "Formulaire d'opérations vide ou invalide",
+ }
+ )
# Returning BAD REQUEST if errors
if data["errors"]:
@@ -1038,6 +1041,7 @@ def kpsul_perform_operations(request):
# Pre-saving (no commit)
operationgroup = operationgroup_form.save(commit=False)
operations = operation_formset.save(commit=False)
+ on_acc = operationgroup.on_acc
# Retrieving COF grant
cof_grant = kfet_config.subvention_cof
@@ -1051,13 +1055,13 @@ def kpsul_perform_operations(request):
to_addcost_for_balance = 0 # For balance of addcost_for
to_checkout_balance = 0 # For balance of selected checkout
to_articles_stocks = defaultdict(lambda: 0) # For stocks articles
- is_addcost = all(
- (addcost_for, addcost_amount, addcost_for != operationgroup.on_acc)
- )
- need_comment = operationgroup.on_acc.need_comment
+ is_addcost = all((addcost_for, addcost_amount, addcost_for != on_acc))
+ need_comment = on_acc.need_comment
- if operationgroup.on_acc.is_frozen:
- data["errors"]["frozen"] = [operationgroup.on_acc.trigramme]
+ if on_acc.is_frozen:
+ data["errors"].append(
+ {"code": "frozen_acc", "message": f"Le compte {on_acc.trigramme} est gelé"}
+ )
# Filling data of each operations
# + operationgroup + calculating other stuffs
@@ -1069,19 +1073,23 @@ def kpsul_perform_operations(request):
operation.addcost_amount = addcost_amount * operation.article_nb
operation.amount -= operation.addcost_amount
to_addcost_for_balance += operation.addcost_amount
- if operationgroup.on_acc.is_cash:
+ if on_acc.is_cash:
to_checkout_balance += -operation.amount
- if (
- operationgroup.on_acc.is_cof
- and operation.article.category.has_reduction
- ):
+ if on_acc.is_cof and operation.article.category.has_reduction:
if is_addcost and operation.article.category.has_addcost:
operation.addcost_amount /= cof_grant_divisor
operation.amount = operation.amount / cof_grant_divisor
to_articles_stocks[operation.article] -= operation.article_nb
else:
- if operationgroup.on_acc.is_cash:
- data["errors"]["account"] = "LIQ"
+ if on_acc.is_cash:
+ data["errors"].append(
+ {
+ "code": "invalid_liq",
+ "message": (
+ "Impossible de compter autre chose que des achats sur LIQ"
+ ),
+ }
+ )
if operation.type != Operation.EDIT:
to_checkout_balance += operation.amount
operationgroup.amount += operation.amount
@@ -1090,41 +1098,42 @@ def kpsul_perform_operations(request):
if operation.type == Operation.EDIT:
required_perms.add("kfet.edit_balance_account")
need_comment = True
- if operationgroup.on_acc.is_cof:
+ if on_acc.is_cof:
to_addcost_for_balance = to_addcost_for_balance / cof_grant_divisor
- (perms, stop) = operationgroup.on_acc.perms_to_perform_operation(
- amount=operationgroup.amount
- )
+ (perms, stop) = on_acc.perms_to_perform_operation(amount=operationgroup.amount)
required_perms |= perms
+ if stop:
+ data["errors"].append(
+ {
+ "code": "negative",
+ "message": f"Le compte {on_acc.trigramme} a un solde insuffisant.",
+ }
+ )
+
if need_comment:
operationgroup.comment = operationgroup.comment.strip()
if not operationgroup.comment:
- data["errors"]["need_comment"] = True
+ data["need_comment"] = True
- if data["errors"]:
+ if data["errors"] or "need_comment" in data:
return JsonResponse(data, status=400)
- if stop 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:
- data["errors"]["negative"] = [operationgroup.on_acc.trigramme]
+ if not request.user.has_perms(required_perms):
+ data["missing_perms"] = get_missing_perms(required_perms, request.user)
return JsonResponse(data, status=403)
# If 1 perm is required, filling who perform the operations
if required_perms:
operationgroup.valid_by = request.user.profile.account_kfet
# Filling cof status for statistics
- operationgroup.is_cof = operationgroup.on_acc.is_cof
+ operationgroup.is_cof = on_acc.is_cof
# Starting transaction to ensure data consistency
with transaction.atomic():
# If not cash account,
# saving account's balance and adding to Negative if not in
- on_acc = operationgroup.on_acc
if not on_acc.is_cash:
(
Account.objects.filter(pk=on_acc.pk).update(
@@ -1148,13 +1157,10 @@ def kpsul_perform_operations(request):
# Saving operation group
operationgroup.save()
- data["operationgroup"] = operationgroup.pk
-
# Filling operationgroup id for each operations and saving
for operation in operations:
operation.group = operationgroup
operation.save()
- data["operations"].append(operation.pk)
# Updating articles stock
for article in to_articles_stocks:
@@ -1177,7 +1183,7 @@ def kpsul_perform_operations(request):
"valid_by__trigramme": (
operationgroup.valid_by and operationgroup.valid_by.trigramme or None
),
- "on_acc__trigramme": operationgroup.on_acc.trigramme,
+ "on_acc__trigramme": on_acc.trigramme,
"entries": [],
}
]
@@ -1218,7 +1224,7 @@ def kpsul_perform_operations(request):
@kfet_password_auth
def cancel_operations(request):
# Pour la réponse
- data = {"canceled": [], "warnings": {}, "errors": {}}
+ data = {"canceled": [], "warnings": {}, "errors": []}
# Checking if BAD REQUEST (opes_pk not int or not existing)
try:
@@ -1227,29 +1233,41 @@ def cancel_operations(request):
map(int, filter(None, request.POST.getlist("operations[]", [])))
)
except ValueError:
+ data["errors"].append(
+ {"code": "invalid_request", "message": "Requête invalide !"}
+ )
return JsonResponse(data, status=400)
+
opes_all = Operation.objects.select_related(
"group", "group__on_acc", "group__on_acc__negative"
).filter(pk__in=opes_post)
opes_pk = [ope.pk for ope in opes_all]
opes_notexisting = [ope for ope in opes_post if ope not in opes_pk]
if opes_notexisting:
- data["errors"]["opes_notexisting"] = opes_notexisting
+ data["errors"].append(
+ {
+ "code": "cancel_missing",
+ "message": "Opérations inexistantes : {}".format(
+ ", ".join(map(str, opes_notexisting))
+ ),
+ }
+ )
return JsonResponse(data, status=400)
opes_already_canceled = [] # Déjà annulée
opes = [] # Pas déjà annulée
required_perms = set()
- stop_all = False
cancel_duration = kfet_config.cancel_duration
- to_accounts_balances = defaultdict(
- lambda: 0
- ) # Modifs à faire sur les balances des comptes
- to_groups_amounts = defaultdict(
- lambda: 0
- ) # ------ sur les montants des groupes d'opé
- to_checkouts_balances = defaultdict(lambda: 0) # ------ sur les balances de caisses
- to_articles_stocks = defaultdict(lambda: 0) # ------ sur les stocks d'articles
+
+ # Modifs à faire sur les balances des comptes
+ to_accounts_balances = defaultdict(int)
+ # ------ sur les montants des groupes d'opé
+ to_groups_amounts = defaultdict(int)
+ # ------ sur les balances de caisses
+ to_checkouts_balances = defaultdict(int)
+ # ------ sur les stocks d'articles
+ to_articles_stocks = defaultdict(int)
+
for ope in opes_all:
if ope.canceled_at:
# Opération déjà annulée, va pour un warning en Response
@@ -1320,16 +1338,22 @@ def cancel_operations(request):
amount=to_accounts_balances[account]
)
required_perms |= perms
- stop_all = stop_all or stop
if stop:
negative_accounts.append(account.trigramme)
- 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
+ if negative_accounts:
+ data["errors"].append(
+ {
+ "code": "negative",
+ "message": "Solde insuffisant pour les comptes suivants : {}".format(
+ ", ".join(negative_accounts)
+ ),
+ }
+ )
+ return JsonResponse(data, status=400)
+
+ if not request.user.has_perms(required_perms):
+ data["missing_perms"] = get_missing_perms(required_perms, request.user)
return JsonResponse(data, status=403)
canceled_by = required_perms and request.user.profile.account_kfet or None
@@ -1657,12 +1681,36 @@ def transfers_create(request):
@teamkfet_required
@kfet_password_auth
def perform_transfers(request):
- data = {"errors": {}, "transfers": [], "transfergroup": 0}
+ data = {"errors": []}
# Checking transfer_formset
transfer_formset = TransferFormSet(request.POST)
- if not transfer_formset.is_valid():
- return JsonResponse({"errors": list(transfer_formset.errors)}, status=400)
+ try:
+ if not transfer_formset.is_valid():
+ for form_errors in transfer_formset.errors:
+ for (field, errors) in form_errors.items():
+ if field == "amount":
+ for error in errors:
+ data["errors"].append({"code": "amount", "message": error})
+ else:
+ # C'est compliqué de trouver le compte qui pose problème...
+ acc_error = True
+
+ if acc_error:
+ data["errors"].append(
+ {
+ "code": "invalid_acc",
+ "message": "L'un des comptes est invalide ou manquant",
+ }
+ )
+
+ return JsonResponse(data, status=400)
+
+ except ValidationError:
+ data["errors"].append(
+ {"code": "invalid_request", "message": "Requête invalide"}
+ )
+ return JsonResponse(data, status=400)
transfers = transfer_formset.save(commit=False)
@@ -1670,14 +1718,12 @@ def perform_transfers(request):
required_perms = set(
["kfet.add_transfer"]
) # Required perms to perform all transfers
- to_accounts_balances = defaultdict(lambda: 0) # For balances of accounts
+ to_accounts_balances = defaultdict(int) # 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
-
negative_accounts = []
# Checking if ok on all accounts
frozen = set()
@@ -1689,20 +1735,34 @@ def perform_transfers(request):
amount=to_accounts_balances[account]
)
required_perms |= perms
- stop_all = stop_all or stop
if stop:
negative_accounts.append(account.trigramme)
- if len(frozen):
- data["errors"]["frozen"] = list(frozen)
+ if frozen:
+ data["errors"].append(
+ {
+ "code": "frozen",
+ "message": "Les comptes suivants sont gelés : {}".format(
+ ", ".join(frozen)
+ ),
+ }
+ )
+
+ if negative_accounts:
+ data["errors"].append(
+ {
+ "code": "negative",
+ "message": "Solde insuffisant pour les comptes suivants : {}".format(
+ ", ".join(negative_accounts)
+ ),
+ }
+ )
+
+ if data["errors"]:
return JsonResponse(data, status=400)
- 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
+ if not request.user.has_perms(required_perms):
+ data["missing_perms"] = get_missing_perms(required_perms, request.user)
return JsonResponse(data, status=403)
# Creating transfer group
@@ -1724,22 +1784,20 @@ def perform_transfers(request):
# Saving transfer group
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)
+ return JsonResponse({})
@teamkfet_required
@kfet_password_auth
def cancel_transfers(request):
# Pour la réponse
- data = {"canceled": [], "warnings": {}, "errors": {}}
+ data = {"canceled": [], "warnings": {}, "errors": []}
# Checking if BAD REQUEST (transfers_pk not int or not existing)
try:
@@ -1748,7 +1806,11 @@ def cancel_transfers(request):
map(int, filter(None, request.POST.getlist("transfers[]", [])))
)
except ValueError:
+ data["errors"].append(
+ {"code": "invalid_request", "message": "Requête invalide !"}
+ )
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)
@@ -1757,17 +1819,23 @@ def cancel_transfers(request):
transfer for transfer in transfers_post if transfer not in transfers_pk
]
if transfers_notexisting:
- data["errors"]["transfers_notexisting"] = transfers_notexisting
+ data["errors"].append(
+ {
+ "code": "cancel_missing",
+ "message": "Transferts inexistants : {}".format(
+ ", ".join(map(str, transfers_notexisting))
+ ),
+ }
+ )
return JsonResponse(data, status=400)
- transfers_already_canceled = [] # Déjà annulée
- transfers = [] # Pas déjà annulée
+ transfers_already_canceled = [] # Déjà annulés
+ transfers = [] # Pas déjà annulés
required_perms = set()
- stop_all = False
cancel_duration = kfet_config.cancel_duration
- to_accounts_balances = defaultdict(
- lambda: 0
- ) # Modifs à faire sur les balances des comptes
+
+ # Modifs à faire sur les balances des comptes
+ to_accounts_balances = defaultdict(int)
for transfer in transfers_all:
if transfer.canceled_at:
# Transfert déjà annulé, va pour un warning en Response
@@ -1795,16 +1863,22 @@ def cancel_transfers(request):
amount=to_accounts_balances[account]
)
required_perms |= perms
- stop_all = stop_all or stop
if stop:
negative_accounts.append(account.trigramme)
- 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
+ if negative_accounts:
+ data["errors"].append(
+ {
+ "code": "negative",
+ "message": "Solde insuffisant pour les comptes suivants : {}".format(
+ ", ".join(negative_accounts)
+ ),
+ }
+ )
+ return JsonResponse(data, status=400)
+
+ if not request.user.has_perms(required_perms):
+ data["missing_perms"] = get_missing_perms(required_perms, request.user)
return JsonResponse(data, status=403)
canceled_by = required_perms and request.user.profile.account_kfet or None