diff --git a/apps/permission/models.py b/apps/permission/models.py
index 79148fe470488c9267dbad996590b20cba9cc1a0..beace783a4006824575f962bc525ffaee0ab0249 100644
--- a/apps/permission/models.py
+++ b/apps/permission/models.py
@@ -4,6 +4,7 @@
 import functools
 import json
 import operator
+from time import sleep
 
 from django.contrib.contenttypes.models import ContentType
 from django.core.exceptions import ValidationError
@@ -44,6 +45,14 @@ class InstancedPermission:
                 else:
                     oldpk = obj.pk
                 # Ensure previous models are deleted
+                count = 0
+                while count < 1000:
+                    if self.model.model_class().objects.filter(pk=obj.pk).exists():
+                        # If the object exists, that means that one permission is currently checked.
+                        # We wait before the other permission, at most 1 second.
+                        sleep(1)
+                        continue
+                    break
                 for o in self.model.model_class().objects.filter(pk=obj.pk).all():
                     o._force_delete = True
                     Model.delete(o)
diff --git a/apps/wei/views.py b/apps/wei/views.py
index f2ac40dc6988e3ae3f3b1a357146c924f3fa7911..2210a347019db58979a323497801d72e9a04a949 100644
--- a/apps/wei/views.py
+++ b/apps/wei/views.py
@@ -17,6 +17,7 @@ from django.http import HttpResponse
 from django.shortcuts import redirect
 from django.template.loader import render_to_string
 from django.urls import reverse_lazy
+from django.utils import timezone
 from django.views import View
 from django.views.generic import DetailView, UpdateView, CreateView, RedirectView, TemplateView
 from django.utils.translation import gettext_lazy as _
@@ -56,7 +57,11 @@ class WEIListView(ProtectQuerysetMixin, LoginRequiredMixin, SingleTableView):
 
     def get_context_data(self, **kwargs):
         context = super().get_context_data(**kwargs)
-        context["can_create_wei"] = PermissionBackend.check_perm(self.request.user, "wei.add_weiclub", WEIClub())
+        context["can_create_wei"] = PermissionBackend.check_perm(self.request.user, "wei.add_weiclub", WEIClub(
+            year=0,
+            date_start=timezone.now().date(),
+            date_end=timezone.now().date(),
+        ))
         return context
 
 
diff --git a/static/js/transfer.js b/static/js/transfer.js
index 4234e775ea623fae3d4a95b4694b3568e0e75507..ba0bf9e312bb12b16c4edc7d6eaff739764888d8 100644
--- a/static/js/transfer.js
+++ b/static/js/transfer.js
@@ -14,8 +14,14 @@ function reset(refresh=true) {
     dests.length = 0;
     $("#source_note_list").html("");
     $("#dest_note_list").html("");
-    $("#amount").val("");
-    $("#reason").val("");
+    let amount_field = $("#amount");
+    amount_field.val("");
+    amount_field.removeClass('is-invalid');
+    $("#amount-required").html("");
+    let reason_field = $("#reason");
+    reason_field.val("");
+    reason_field.removeClass('is-invalid');
+    $("#reason-required").html("");
     $("#last_name").val("");
     $("#first_name").val("");
     $("#bank").val("");
@@ -140,7 +146,9 @@ $(document).ready(function() {
 
     $("#source_me").click(function() {
         // Shortcut to set the current user as the only emitter
-        reset(false);
+        sources_notes_display.length = 0;
+        sources.length = 0;
+        $("#source_note_list").html("");
 
         let source_note = $("#source_note");
         source_note.focus();
@@ -170,15 +178,45 @@ $(document).ready(function() {
 });
 
 $("#btn_transfer").click(function() {
+    let error = false;
+
+    let amount_field = $("#amount");
+    amount_field.removeClass('is-invalid');
+    $("#amount-required").html("");
+
+    let reason_field = $("#reason");
+    reason_field.removeClass('is-invalid');
+    $("#reason-required").html("");
+
+    if (!amount_field.val() || isNaN(amount_field.val()) || amount_field.val() <= 0) {
+        amount_field.addClass('is-invalid');
+        $("#amount-required").html("<strong>Ce champ est requis et doit comporter un nombre décimal strictement positif.</strong>");
+        error = true;
+    }
+
+    if (!reason_field.val()) {
+        reason_field.addClass('is-invalid');
+        $("#reason-required").html("<strong>Ce champ est requis.</strong>");
+        error = true;
+    }
+
+    if (error)
+        return;
+
+    let amount = 100 * amount_field.val();
+    let reason = reason_field.val();
+
     if ($("#type_transfer").is(':checked')) {
-        sources_notes_display.forEach(function (source) {
-            dests_notes_display.forEach(function (dest) {
+
+        // We copy the arrays to ensure that transactions are well-processed even if the form is reset
+        [...sources_notes_display].forEach(function (source) {
+            [...dests_notes_display].forEach(function (dest) {
                 $.post("/api/note/transaction/transaction/",
                     {
                         "csrfmiddlewaretoken": CSRF_TOKEN,
                         "quantity": source.quantity * dest.quantity,
-                        "amount": 100 * $("#amount").val(),
-                        "reason": $("#reason").val(),
+                        "amount": amount,
+                        "reason": reason,
                         "valid": true,
                         "polymorphic_ctype": TRANSFER_POLYMORPHIC_CTYPE,
                         "resourcetype": "Transaction",
@@ -188,7 +226,7 @@ $("#btn_transfer").click(function() {
                         "destination_alias": dest.name
                     }).done(function () {
                         addMsg("Le transfert de "
-                            + pretty_money(source.quantity * dest.quantity * 100 * $("#amount").val()) + " de la note " + source.name
+                            + pretty_money(source.quantity * dest.quantity * amount) + " de la note " + source.name
                             + " vers la note " + dest.name + " a été fait avec succès !", "success", 10000);
 
                         reset();
@@ -197,8 +235,8 @@ $("#btn_transfer").click(function() {
                         {
                             "csrfmiddlewaretoken": CSRF_TOKEN,
                             "quantity": source.quantity * dest.quantity,
-                            "amount": 100 * $("#amount").val(),
-                            "reason": $("#reason").val(),
+                            "amount": amount,
+                            "reason": reason,
                             "valid": false,
                             "invalidity_reason": "Solde insuffisant",
                             "polymorphic_ctype": TRANSFER_POLYMORPHIC_CTYPE,
@@ -209,12 +247,12 @@ $("#btn_transfer").click(function() {
                             "destination_alias": dest.name
                         }).done(function () {
                             addMsg("Le transfert de "
-                                + pretty_money(source.quantity * dest.quantity * 100 * $("#amount").val()) + " de la note " + source.name
+                                + pretty_money(source.quantity * dest.quantity * amount) + " de la note " + source.name
                                 + " vers la note " + dest.name + " a échoué : Solde insuffisant", "danger", 10000);
                         }).fail(function (err) {
                             addMsg("Le transfert de "
-                                + pretty_money(source.quantity * dest.quantity * 100 * $("#amount").val()) + " de la note " + source.name
-                                + " vers la note " + dest.name + " a échoué : " + JSON.parse(err.responseText)["detail"], "danger", 10000);
+                                + pretty_money(source.quantity * dest.quantity * amount) + " de la note " + source.name
+                                + " vers la note " + dest.name + " a échoué : " + err.responseText, "danger");
                     });
                 });
             });
@@ -222,7 +260,7 @@ $("#btn_transfer").click(function() {
     } else if ($("#type_credit").is(':checked') || $("#type_debit").is(':checked')) {
         let special_note = $("#credit_type").val();
         let user_note;
-        let given_reason = $("#reason").val();
+        let given_reason = reason;
         let source, dest, reason;
         if ($("#type_credit").is(':checked')) {
             user_note = dests_notes_display[0].note.id;
@@ -244,7 +282,7 @@ $("#btn_transfer").click(function() {
             {
                 "csrfmiddlewaretoken": CSRF_TOKEN,
                 "quantity": 1,
-                "amount": 100 * $("#amount").val(),
+                "amount": amount,
                 "reason": reason,
                 "valid": true,
                 "polymorphic_ctype": SPECIAL_TRANSFER_POLYMORPHIC_CTYPE,
diff --git a/templates/note/amount_input.html b/templates/note/amount_input.html
index 6ef4a53abd68980520621016d962bde22b2db91c..cd8cd201e103c148c68d8bca217e8cc0eeaed708 100644
--- a/templates/note/amount_input.html
+++ b/templates/note/amount_input.html
@@ -8,4 +8,5 @@
     <div class="input-group-append">
         <span class="input-group-text">€</span>
     </div>
+    <p id="amount-required" class="invalid-feedback"></p>
 </div>
\ No newline at end of file
diff --git a/templates/note/transaction_form.html b/templates/note/transaction_form.html
index cb7df094d9f009aff1ce8d1682346bb3d9227441..b761490d933cc688d2ed0ae41341c1782536e6f5 100644
--- a/templates/note/transaction_form.html
+++ b/templates/note/transaction_form.html
@@ -100,7 +100,8 @@ SPDX-License-Identifier: GPL-2.0-or-later
                     <div class="form-row">
                         <div class="col-md-12">
                             <label for="reason">{% trans "Reason" %} :</label>
-                            <input class="form-control mx-auto d-block" type="text" id="reason" required />
+                            <input class="form-control mx-auto d-block" type="text" id="reason" />
+                            <p id="reason-required" class="invalid-feedback"></p>
                         </div>
                     </div>