From 6e13e4fb3698db4ae60847c88b86673a74778a2b 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 created custom month field fixed formatting fixed imports --- counter/migrations/0032_invoicecall.py | 47 +++++++++++++++ counter/models.py | 43 ++++++++++++++ counter/templates/counter/invoices_call.jinja | 45 +++++++++------ counter/views/invoice.py | 57 ++++++++++++++++++- 4 files changed, 172 insertions(+), 20 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..a51e8b27 --- /dev/null +++ b/counter/migrations/0032_invoicecall.py @@ -0,0 +1,47 @@ +# Generated by Django 5.2 on 2025-06-11 12:53 + +import django.db.models.deletion +from django.db import migrations, models + +import counter.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", + counter.models.MonthField( + max_length=7, verbose_name="invoice date" + ), + ), + ( + "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..89681e62 100644 --- a/counter/models.py +++ b/counter/models.py @@ -1362,3 +1362,46 @@ class ReturnableProductBalance(models.Model): f"return balance of {self.customer} " f"for {self.returnable.product_id} : {self.balance}" ) + + +class MonthField(models.DateField): + description = _("Year + month field") + + def __init__(self, *args, **kwargs): + kwargs["max_length"] = 7 + super().__init__(*args, **kwargs) + + def db_type(self, connection): + return "char(7)" + + def from_db_value(self, value, expression, connection): + if value is None: + return value + year, month = map(value.split("-")) + return date(year, month, 1) + + def get_prep_value(self, value): + if isinstance(value, date): + return value.strftime("%Y-%m") + elif isinstance(value, str): + try: + datetime.strptime(value, "%Y-%m") + except ValueError: + raise ValueError("invalid format for date (use YYYY-mm)") from None + elif value is None: + return value + else: + raise TypeError("Invalid type for MonthField") + + +class InvoiceCall(models.Model): + validated = models.BooleanField(verbose_name=_("is validated")) + club = models.ForeignKey(Club, on_delete=models.CASCADE) + month = MonthField(verbose_name=_("invoice date")) + + 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..6adce714 100644 --- a/counter/views/invoice.py +++ b/counter/views/invoice.py @@ -12,7 +12,7 @@ # OR WITHIN THE LOCAL FILE "LICENSE" # # -from datetime import datetime, timedelta +from datetime import date, datetime, timedelta from datetime import timezone as tz from django.db.models import F @@ -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,57 @@ 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=date(start_date.year, start_date.month, 1), 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( + month=date(year, month, 1), 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.get(club_name) + + if invoice_call: + if invoice_call.validated != is_checked: + invoice_call.validated = is_checked + invoice_call.save() + else: + InvoiceCall.objects.create( + month=date(year, month, 1), + club=club_map[club_name], + validated=is_checked, + ) + + from django.shortcuts import redirect + + return redirect(f"{request.path}?month={request.POST.get('month', '')}")