From 2c712d6454c9aa7ac568b2b204cd95ff46258573 Mon Sep 17 00:00:00 2001 From: Kenneth SOARES Date: Mon, 2 Jun 2025 16:51:29 +0200 Subject: [PATCH] added checkbox for invoice calls formatting separated logic for get and post --- counter/migrations/0032_invoicecall.py | 44 +++++++++++++++ counter/models.py | 17 ++++++ counter/templates/counter/invoices_call.jinja | 45 +++++++++------ counter/views/invoice.py | 56 ++++++++++++++++++- 4 files changed, 143 insertions(+), 19 deletions(-) create mode 100644 counter/migrations/0032_invoicecall.py diff --git a/counter/migrations/0032_invoicecall.py b/counter/migrations/0032_invoicecall.py new file mode 100644 index 00000000..3c593943 --- /dev/null +++ b/counter/migrations/0032_invoicecall.py @@ -0,0 +1,44 @@ +# Generated by Django 5.2 on 2025-06-02 14:29 + +import django.db.models.deletion +from django.db import migrations, models + + +class Migration(migrations.Migration): + dependencies = [ + ("club", "0014_alter_club_options_rename_unix_name_club_slug_name_and_more"), + ("counter", "0031_alter_counter_options"), + ] + + operations = [ + migrations.CreateModel( + name="InvoiceCall", + fields=[ + ( + "id", + models.AutoField( + auto_created=True, + primary_key=True, + serialize=False, + verbose_name="ID", + ), + ), + ("validated", models.BooleanField(verbose_name="is validated")), + ( + "month", + models.PositiveSmallIntegerField(verbose_name="invoice month"), + ), + ("year", models.PositiveIntegerField(verbose_name="invoice year")), + ( + "club", + models.ForeignKey( + on_delete=django.db.models.deletion.CASCADE, to="club.club" + ), + ), + ], + options={ + "verbose_name": "Invoice call", + "verbose_name_plural": "Invoice calls", + }, + ), + ] diff --git a/counter/models.py b/counter/models.py index 3515e081..8f0b898e 100644 --- a/counter/models.py +++ b/counter/models.py @@ -1362,3 +1362,20 @@ class ReturnableProductBalance(models.Model): f"return balance of {self.customer} " f"for {self.returnable.product_id} : {self.balance}" ) + + +class InvoiceCall(models.Model): + validated = models.BooleanField(verbose_name=_("is validated")) + club = models.ForeignKey(Club, on_delete=models.CASCADE) + + # le formattage des dates dans les models Django ne permet pas d'exclure le jour + # donc on utilise deux entiers plutot qu'un datefield avec jour fixe + month = models.PositiveSmallIntegerField(verbose_name=_("invoice month")) + year = models.PositiveIntegerField(verbose_name=_("invoice year")) + + class Meta: + verbose_name = _("Invoice call") + verbose_name_plural = _("Invoice calls") + + def __str__(self): + return f"invoice call of {self.month}/{self.year} made by {self.club}" diff --git a/counter/templates/counter/invoices_call.jinja b/counter/templates/counter/invoices_call.jinja index bdc43d31..6ca1004b 100644 --- a/counter/templates/counter/invoices_call.jinja +++ b/counter/templates/counter/invoices_call.jinja @@ -15,23 +15,32 @@ -
-

{% trans %}CB Payments{% endtrans %} : {{ sum_cb }} €

-
- - - - - - - {% for i in sums %} - - - - - {% endfor %} - -
{% trans %}Club{% endtrans %}{% trans %}Sum{% endtrans %}
{{ i['club__name'] }}{{"%.2f"|format(i['selling_sum'])}} €
-{% endblock %} +
+ {% csrf_token %} +
+

{% trans %}CB Payments{% endtrans %} : {{ sum_cb }} €

+
+ + + + + + + + {% for i in sums %} + + + + + + {% endfor %} + +
{% trans %}Club{% endtrans %}{% trans %}Sum{% endtrans %}{% trans %}Validated{% endtrans %}
{{ i['club__name'] }}{{"%.2f"|format(i['selling_sum'])}} € + +
+ + +
+{% endblock %} \ No newline at end of file diff --git a/counter/views/invoice.py b/counter/views/invoice.py index 34e97a40..03672548 100644 --- a/counter/views/invoice.py +++ b/counter/views/invoice.py @@ -20,7 +20,7 @@ from django.utils import timezone from django.views.generic import TemplateView from counter.fields import CurrencyField -from counter.models import Refilling, Selling +from counter.models import Club, InvoiceCall, Refilling, Selling from counter.views.mixins import CounterAdminMixin, CounterAdminTabsMixin @@ -79,4 +79,58 @@ class InvoiceCallView(CounterAdminTabsMixin, CounterAdminMixin, TemplateView): .exclude(selling_sum=None) .order_by("-selling_sum") ) + + # une query pour tous les clubs qu'on met dans un dico dont la clé est le nom du club + club_names = [i["club__name"] for i in kwargs["sums"]] + clubs = Club.objects.filter(name__in=club_names) + + # et une query pour les factures + invoice_calls = InvoiceCall.objects.filter( + month=start_date.month, year=start_date.year, club__in=clubs + ) + + invoice_statuses = {ic.club.name: ic.validated for ic in invoice_calls} + + kwargs["validated"] = invoice_statuses return kwargs + + def post(self, request, *args, **kwargs): + if request.POST["month"]: + start_date = datetime.strptime(request.POST["month"], "%Y-%m") + + year = start_date.year + month = start_date.month + + club_names = list( + Selling.objects.filter(date__year=year, date__month=month) + .values_list("club__name", flat=True) + .distinct() + ) + + clubs = Club.objects.filter(name__in=club_names) + club_map = {club.name: club for club in clubs} + + invoice_calls = InvoiceCall.objects.filter( + year=year, month=month, club__in=clubs + ) + invoice_statuses = {ic.club.name: ic for ic in invoice_calls} + + for club_name in club_names: + is_checked = f"validate_{club_name}" in request.POST + invoice_call = invoice_statuses[club_name] + + if invoice_call: + if invoice_call.validated != is_checked: + invoice_call.validated = is_checked + invoice_call.save() + else: + InvoiceCall.objects.create( + year=year, + month=month, + club=club_map[club_name], + validated=is_checked, + ) + + from django.shortcuts import redirect + + return redirect(f"{request.path}?month={request.POST.get('month', '')}")