mirror of
				https://gitlab.crans.org/bde/nk20
				synced 2025-11-04 09:12:11 +01:00 
			
		
		
		
	Improve transfer UI
This commit is contained in:
		@@ -4,6 +4,7 @@
 | 
				
			|||||||
import functools
 | 
					import functools
 | 
				
			||||||
import json
 | 
					import json
 | 
				
			||||||
import operator
 | 
					import operator
 | 
				
			||||||
 | 
					from time import sleep
 | 
				
			||||||
 | 
					
 | 
				
			||||||
from django.contrib.contenttypes.models import ContentType
 | 
					from django.contrib.contenttypes.models import ContentType
 | 
				
			||||||
from django.core.exceptions import ValidationError
 | 
					from django.core.exceptions import ValidationError
 | 
				
			||||||
@@ -44,6 +45,14 @@ class InstancedPermission:
 | 
				
			|||||||
                else:
 | 
					                else:
 | 
				
			||||||
                    oldpk = obj.pk
 | 
					                    oldpk = obj.pk
 | 
				
			||||||
                # Ensure previous models are deleted
 | 
					                # 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():
 | 
					                for o in self.model.model_class().objects.filter(pk=obj.pk).all():
 | 
				
			||||||
                    o._force_delete = True
 | 
					                    o._force_delete = True
 | 
				
			||||||
                    Model.delete(o)
 | 
					                    Model.delete(o)
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -17,6 +17,7 @@ from django.http import HttpResponse
 | 
				
			|||||||
from django.shortcuts import redirect
 | 
					from django.shortcuts import redirect
 | 
				
			||||||
from django.template.loader import render_to_string
 | 
					from django.template.loader import render_to_string
 | 
				
			||||||
from django.urls import reverse_lazy
 | 
					from django.urls import reverse_lazy
 | 
				
			||||||
 | 
					from django.utils import timezone
 | 
				
			||||||
from django.views import View
 | 
					from django.views import View
 | 
				
			||||||
from django.views.generic import DetailView, UpdateView, CreateView, RedirectView, TemplateView
 | 
					from django.views.generic import DetailView, UpdateView, CreateView, RedirectView, TemplateView
 | 
				
			||||||
from django.utils.translation import gettext_lazy as _
 | 
					from django.utils.translation import gettext_lazy as _
 | 
				
			||||||
@@ -56,7 +57,11 @@ class WEIListView(ProtectQuerysetMixin, LoginRequiredMixin, SingleTableView):
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    def get_context_data(self, **kwargs):
 | 
					    def get_context_data(self, **kwargs):
 | 
				
			||||||
        context = super().get_context_data(**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
 | 
					        return context
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -14,8 +14,14 @@ function reset(refresh=true) {
 | 
				
			|||||||
    dests.length = 0;
 | 
					    dests.length = 0;
 | 
				
			||||||
    $("#source_note_list").html("");
 | 
					    $("#source_note_list").html("");
 | 
				
			||||||
    $("#dest_note_list").html("");
 | 
					    $("#dest_note_list").html("");
 | 
				
			||||||
    $("#amount").val("");
 | 
					    let amount_field = $("#amount");
 | 
				
			||||||
    $("#reason").val("");
 | 
					    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("");
 | 
					    $("#last_name").val("");
 | 
				
			||||||
    $("#first_name").val("");
 | 
					    $("#first_name").val("");
 | 
				
			||||||
    $("#bank").val("");
 | 
					    $("#bank").val("");
 | 
				
			||||||
@@ -140,7 +146,9 @@ $(document).ready(function() {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    $("#source_me").click(function() {
 | 
					    $("#source_me").click(function() {
 | 
				
			||||||
        // Shortcut to set the current user as the only emitter
 | 
					        // 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");
 | 
					        let source_note = $("#source_note");
 | 
				
			||||||
        source_note.focus();
 | 
					        source_note.focus();
 | 
				
			||||||
@@ -170,15 +178,45 @@ $(document).ready(function() {
 | 
				
			|||||||
});
 | 
					});
 | 
				
			||||||
 | 
					
 | 
				
			||||||
$("#btn_transfer").click(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')) {
 | 
					    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/",
 | 
					                $.post("/api/note/transaction/transaction/",
 | 
				
			||||||
                    {
 | 
					                    {
 | 
				
			||||||
                        "csrfmiddlewaretoken": CSRF_TOKEN,
 | 
					                        "csrfmiddlewaretoken": CSRF_TOKEN,
 | 
				
			||||||
                        "quantity": source.quantity * dest.quantity,
 | 
					                        "quantity": source.quantity * dest.quantity,
 | 
				
			||||||
                        "amount": 100 * $("#amount").val(),
 | 
					                        "amount": amount,
 | 
				
			||||||
                        "reason": $("#reason").val(),
 | 
					                        "reason": reason,
 | 
				
			||||||
                        "valid": true,
 | 
					                        "valid": true,
 | 
				
			||||||
                        "polymorphic_ctype": TRANSFER_POLYMORPHIC_CTYPE,
 | 
					                        "polymorphic_ctype": TRANSFER_POLYMORPHIC_CTYPE,
 | 
				
			||||||
                        "resourcetype": "Transaction",
 | 
					                        "resourcetype": "Transaction",
 | 
				
			||||||
@@ -188,7 +226,7 @@ $("#btn_transfer").click(function() {
 | 
				
			|||||||
                        "destination_alias": dest.name
 | 
					                        "destination_alias": dest.name
 | 
				
			||||||
                    }).done(function () {
 | 
					                    }).done(function () {
 | 
				
			||||||
                        addMsg("Le transfert de "
 | 
					                        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);
 | 
					                            + " vers la note " + dest.name + " a été fait avec succès !", "success", 10000);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                        reset();
 | 
					                        reset();
 | 
				
			||||||
@@ -197,8 +235,8 @@ $("#btn_transfer").click(function() {
 | 
				
			|||||||
                        {
 | 
					                        {
 | 
				
			||||||
                            "csrfmiddlewaretoken": CSRF_TOKEN,
 | 
					                            "csrfmiddlewaretoken": CSRF_TOKEN,
 | 
				
			||||||
                            "quantity": source.quantity * dest.quantity,
 | 
					                            "quantity": source.quantity * dest.quantity,
 | 
				
			||||||
                            "amount": 100 * $("#amount").val(),
 | 
					                            "amount": amount,
 | 
				
			||||||
                            "reason": $("#reason").val(),
 | 
					                            "reason": reason,
 | 
				
			||||||
                            "valid": false,
 | 
					                            "valid": false,
 | 
				
			||||||
                            "invalidity_reason": "Solde insuffisant",
 | 
					                            "invalidity_reason": "Solde insuffisant",
 | 
				
			||||||
                            "polymorphic_ctype": TRANSFER_POLYMORPHIC_CTYPE,
 | 
					                            "polymorphic_ctype": TRANSFER_POLYMORPHIC_CTYPE,
 | 
				
			||||||
@@ -209,12 +247,12 @@ $("#btn_transfer").click(function() {
 | 
				
			|||||||
                            "destination_alias": dest.name
 | 
					                            "destination_alias": dest.name
 | 
				
			||||||
                        }).done(function () {
 | 
					                        }).done(function () {
 | 
				
			||||||
                            addMsg("Le transfert de "
 | 
					                            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);
 | 
					                                + " vers la note " + dest.name + " a échoué : Solde insuffisant", "danger", 10000);
 | 
				
			||||||
                        }).fail(function (err) {
 | 
					                        }).fail(function (err) {
 | 
				
			||||||
                            addMsg("Le transfert de "
 | 
					                            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é : " + JSON.parse(err.responseText)["detail"], "danger", 10000);
 | 
					                                + " 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')) {
 | 
					    } else if ($("#type_credit").is(':checked') || $("#type_debit").is(':checked')) {
 | 
				
			||||||
        let special_note = $("#credit_type").val();
 | 
					        let special_note = $("#credit_type").val();
 | 
				
			||||||
        let user_note;
 | 
					        let user_note;
 | 
				
			||||||
        let given_reason = $("#reason").val();
 | 
					        let given_reason = reason;
 | 
				
			||||||
        let source, dest, reason;
 | 
					        let source, dest, reason;
 | 
				
			||||||
        if ($("#type_credit").is(':checked')) {
 | 
					        if ($("#type_credit").is(':checked')) {
 | 
				
			||||||
            user_note = dests_notes_display[0].note.id;
 | 
					            user_note = dests_notes_display[0].note.id;
 | 
				
			||||||
@@ -244,7 +282,7 @@ $("#btn_transfer").click(function() {
 | 
				
			|||||||
            {
 | 
					            {
 | 
				
			||||||
                "csrfmiddlewaretoken": CSRF_TOKEN,
 | 
					                "csrfmiddlewaretoken": CSRF_TOKEN,
 | 
				
			||||||
                "quantity": 1,
 | 
					                "quantity": 1,
 | 
				
			||||||
                "amount": 100 * $("#amount").val(),
 | 
					                "amount": amount,
 | 
				
			||||||
                "reason": reason,
 | 
					                "reason": reason,
 | 
				
			||||||
                "valid": true,
 | 
					                "valid": true,
 | 
				
			||||||
                "polymorphic_ctype": SPECIAL_TRANSFER_POLYMORPHIC_CTYPE,
 | 
					                "polymorphic_ctype": SPECIAL_TRANSFER_POLYMORPHIC_CTYPE,
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -8,4 +8,5 @@
 | 
				
			|||||||
    <div class="input-group-append">
 | 
					    <div class="input-group-append">
 | 
				
			||||||
        <span class="input-group-text">€</span>
 | 
					        <span class="input-group-text">€</span>
 | 
				
			||||||
    </div>
 | 
					    </div>
 | 
				
			||||||
 | 
					    <p id="amount-required" class="invalid-feedback"></p>
 | 
				
			||||||
</div>
 | 
					</div>
 | 
				
			||||||
@@ -100,7 +100,8 @@ SPDX-License-Identifier: GPL-2.0-or-later
 | 
				
			|||||||
                    <div class="form-row">
 | 
					                    <div class="form-row">
 | 
				
			||||||
                        <div class="col-md-12">
 | 
					                        <div class="col-md-12">
 | 
				
			||||||
                            <label for="reason">{% trans "Reason" %} :</label>
 | 
					                            <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>
 | 
				
			||||||
                    </div>
 | 
					                    </div>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user