From ecccb005b8bf5144c2cbd66bdd5b9be42c3afeb1 Mon Sep 17 00:00:00 2001 From: catvayor Date: Fri, 21 Mar 2025 10:46:30 +0100 Subject: [PATCH 1/9] feat(cof_clubs): initial period in mass-add --- cof_clubs/forms.py | 1 + 1 file changed, 1 insertion(+) diff --git a/cof_clubs/forms.py b/cof_clubs/forms.py index 83d1840e..d80204ba 100644 --- a/cof_clubs/forms.py +++ b/cof_clubs/forms.py @@ -55,6 +55,7 @@ class ClubBudgetLineCommonForm(Form): accounting_period = forms.ModelChoiceField( label="Exercice comptable", queryset=ClubBudgetAccountingPeriod.objects.filter(is_archived=False), + initial=ClubBudgetAccountingPeriod.objects.filter(is_archived=False).first(), ) label = forms.CharField(label="Libellé", max_length=1000) posted = forms.BooleanField(label="Transactions validées par la trez", initial=True) From cff168f1f69b3fe3b8a940c9d39dcb4afbbee8a2 Mon Sep 17 00:00:00 2001 From: catvayor Date: Fri, 21 Mar 2025 11:06:47 +0100 Subject: [PATCH 2/9] feat(cof_clubs): club edit view --- cof_clubs/templates/cof_clubs/club_detail.html | 2 +- cof_clubs/urls.py | 5 +++-- cof_clubs/views.py | 8 ++++++++ 3 files changed, 12 insertions(+), 3 deletions(-) diff --git a/cof_clubs/templates/cof_clubs/club_detail.html b/cof_clubs/templates/cof_clubs/club_detail.html index c200c86b..c13cf789 100644 --- a/cof_clubs/templates/cof_clubs/club_detail.html +++ b/cof_clubs/templates/cof_clubs/club_detail.html @@ -5,7 +5,7 @@
-

{{ object.name }}

+

{{ object.name }} {% if user.profile.is_buro %}{% endif %}

Respos:
{% for r in object.respos.all %} diff --git a/cof_clubs/urls.py b/cof_clubs/urls.py index 202ac82c..fb54ab30 100644 --- a/cof_clubs/urls.py +++ b/cof_clubs/urls.py @@ -5,6 +5,9 @@ from . import views app_name = "cof_clubs" urlpatterns = [ path("", views.ClubListView.as_view(), name="club-list"), + path("club/add", views.ClubCreateView.as_view(), name="club-create"), + path("club/", views.ClubDetailView.as_view(), name="club-detail"), + path("club//edit", views.ClubEditView.as_view(), name="club-edit"), path( "acct-period/add", views.ClubBudgetAccountingPeriodCreateView.as_view(), @@ -15,8 +18,6 @@ urlpatterns = [ views.ClubBudgetAccountingPeriodUpdateView.as_view(), name="acct-period-update", ), - path("club/", views.ClubDetailView.as_view(), name="club-detail"), - path("club/add", views.ClubCreateView.as_view(), name="club-create"), path( "line///add", views.BudgetLineCreate.as_view(), diff --git a/cof_clubs/views.py b/cof_clubs/views.py index a9548b95..f44288c3 100644 --- a/cof_clubs/views.py +++ b/cof_clubs/views.py @@ -149,6 +149,14 @@ class ClubDetailView(AccessMixin, DetailView): return ctx +class ClubEditView(BuroRequiredMixin, UpdateView): + model = Club + fields = ["name", "description", "respos", "budget_managers"] + + def get_success_url(self): + return reverse("cof_clubs:club-detail", kwargs={"pk": self.object.id}) + + class BudgetLineCreate(BudgetLineAccessMixin, CreateView): model = ClubBudgetLine From 8dbc3336a3a99d58d5ebe0e67e04b4a91f441e62 Mon Sep 17 00:00:00 2001 From: catvayor Date: Thu, 27 Mar 2025 17:53:42 +0100 Subject: [PATCH 3/9] feat(cof_clubs): widget for respo selection chore(nix-pkgs): update to solve django-bulma-forms bug --- cof_clubs/forms.py | 11 ++ .../cof_clubs/_widget_bigmultiselect.html | 154 ++++++++++++++++++ cof_clubs/views.py | 5 +- cof_clubs/widgets.py | 31 ++++ npins/sources.json | 8 +- requirements.txt | 1 + 6 files changed, 204 insertions(+), 6 deletions(-) create mode 100644 cof_clubs/templates/cof_clubs/_widget_bigmultiselect.html create mode 100644 cof_clubs/widgets.py diff --git a/cof_clubs/forms.py b/cof_clubs/forms.py index d80204ba..c263c836 100644 --- a/cof_clubs/forms.py +++ b/cof_clubs/forms.py @@ -5,6 +5,17 @@ from django.forms import Form, modelformset_factory from django.utils.translation import gettext_lazy as _ from .models import Club, ClubBudgetAccountingPeriod, ClubBudgetLine +from .widgets import BigMultiSelect + + +class ClubForm(forms.ModelForm): + class Meta: + model = Club + fields = ["name", "description", "respos", "budget_managers"] + widgets = { + "respos": BigMultiSelect, + "budget_managers": BigMultiSelect, + } class ClubBudgetLineForm(forms.ModelForm): diff --git a/cof_clubs/templates/cof_clubs/_widget_bigmultiselect.html b/cof_clubs/templates/cof_clubs/_widget_bigmultiselect.html new file mode 100644 index 00000000..aa2acd8a --- /dev/null +++ b/cof_clubs/templates/cof_clubs/_widget_bigmultiselect.html @@ -0,0 +1,154 @@ + + + + + + + + + + + + +
+ +
diff --git a/cof_clubs/views.py b/cof_clubs/views.py index f44288c3..09eb036a 100644 --- a/cof_clubs/views.py +++ b/cof_clubs/views.py @@ -15,13 +15,14 @@ from .forms import ( ClubBudgetLineForm, ClubBudgetLineFormSet, ClubBudgetLineFullForm, + ClubForm, ) from .models import Club, ClubBudgetAccountingPeriod, ClubBudgetLine class ClubCreateView(BuroRequiredMixin, SuccessMessageMixin, CreateView): model = Club - fields = ["name", "description", "respos", "budget_managers"] + form_class = ClubForm success_message = "Le club %(name)s a été créé avec succès" @@ -151,7 +152,7 @@ class ClubDetailView(AccessMixin, DetailView): class ClubEditView(BuroRequiredMixin, UpdateView): model = Club - fields = ["name", "description", "respos", "budget_managers"] + form_class = ClubForm def get_success_url(self): return reverse("cof_clubs:club-detail", kwargs={"pk": self.object.id}) diff --git a/cof_clubs/widgets.py b/cof_clubs/widgets.py new file mode 100644 index 00000000..532aded6 --- /dev/null +++ b/cof_clubs/widgets.py @@ -0,0 +1,31 @@ +from django.forms.widgets import Widget +from django.template.loader import render_to_string + + +class BigMultiSelect(Widget): + template_name = "BigMultiSelect" + + def __init__(self, attrs=None, choices=()): + super().__init__(attrs) + # choices can be any iterable, but we may need to render this widget + # multiple times. Thus, collapse it into a list so it can be consumed + # more than once. + self.choices = list(choices) + + def get_context(self, name, value, attrs): + ret = super().get_context(name, value, attrs) + ret["choices"] = self.choices + return ret + + def value_from_datadict(self, data, files, name): + return data.getlist(name) + + def render(self, name, value, attrs=None, renderer=None): + if value is None: + value = [] + attrs["value"] = value + final_attrs = self.build_attrs(self.attrs, attrs) + return render_to_string( + "cof_clubs/_widget_bigmultiselect.html", + self.get_context(name, value, attrs), + ) diff --git a/npins/sources.json b/npins/sources.json index 9ed77931..7f78c348 100644 --- a/npins/sources.json +++ b/npins/sources.json @@ -15,12 +15,12 @@ "type": "Git", "repository": { "type": "Git", - "url": "https://git.hubrecht.ovh/hubrecht/nix-pkgs" + "url": "https://git.hubrecht.ovh/hubrecht/nix-pkgs.git" }, - "branch": "main", - "revision": "ac4ff5a34789ae3398aff9501735b67b6a5a285a", + "branch": "dgnum", + "revision": "7a0e2e660b26ddd67bb8132beb6b13e3a69003a4", "url": null, - "hash": "16n37f74p6h30hhid98vab9w5b08xqj4qcshz2kc1jh67z5n49p6" + "hash": "0xx18q7rifpjq00mghqp280y61biyq5cvnyw6wbwa1zg4iywpv6n" }, "nixpkgs": { "type": "Channel", diff --git a/requirements.txt b/requirements.txt index 65d1d380..9413a7d0 100644 --- a/requirements.txt +++ b/requirements.txt @@ -5,6 +5,7 @@ channels==3.0.5 configparser==7.1.0 django-autocomplete-light==3.11.0 django-bootstrap-form==3.4 +django-bulma-forms==0.1.7 django-cas-ng==5.0.1 django-cors-headers==4.6.0 django-djconfig==0.11.0 From 9e97a76658c921b30c0c38c81afcccb307f6abf5 Mon Sep 17 00:00:00 2001 From: catvayor Date: Fri, 18 Apr 2025 13:10:25 +0200 Subject: [PATCH 4/9] fix(cof_clubs): initial value for accounting period --- cof_clubs/forms.py | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/cof_clubs/forms.py b/cof_clubs/forms.py index c263c836..787eeaf4 100644 --- a/cof_clubs/forms.py +++ b/cof_clubs/forms.py @@ -66,7 +66,13 @@ class ClubBudgetLineCommonForm(Form): accounting_period = forms.ModelChoiceField( label="Exercice comptable", queryset=ClubBudgetAccountingPeriod.objects.filter(is_archived=False), - initial=ClubBudgetAccountingPeriod.objects.filter(is_archived=False).first(), + empty_label=None, ) label = forms.CharField(label="Libellé", max_length=1000) posted = forms.BooleanField(label="Transactions validées par la trez", initial=True) + + def __init__(self, *args, **kwargs): + super().__init__(*args, **kwargs) + self.fields["accounting_period"].initial = ( + ClubBudgetAccountingPeriod.objects.filter(is_archived=False).first() + ) From 8d49006d2dc2ee2e846fc5fa60fa8743b4835698 Mon Sep 17 00:00:00 2001 From: catvayor Date: Wed, 30 Apr 2025 16:54:16 +0200 Subject: [PATCH 5/9] chore(migrations): merge after rebase --- ...erge_0021_delete_club_0023_cofprofile_is_chef.py | 13 +++++++++++++ 1 file changed, 13 insertions(+) create mode 100644 gestioncof/migrations/0024_merge_0021_delete_club_0023_cofprofile_is_chef.py diff --git a/gestioncof/migrations/0024_merge_0021_delete_club_0023_cofprofile_is_chef.py b/gestioncof/migrations/0024_merge_0021_delete_club_0023_cofprofile_is_chef.py new file mode 100644 index 00000000..d7a5e4cf --- /dev/null +++ b/gestioncof/migrations/0024_merge_0021_delete_club_0023_cofprofile_is_chef.py @@ -0,0 +1,13 @@ +# Generated by Django 4.2.16 on 2025-04-30 14:53 + +from django.db import migrations + + +class Migration(migrations.Migration): + + dependencies = [ + ("gestioncof", "0021_delete_club"), + ("gestioncof", "0023_cofprofile_is_chef"), + ] + + operations = [] From 600bf58728af46ca6483a3a9622a144678120b78 Mon Sep 17 00:00:00 2001 From: catvayor Date: Fri, 21 Mar 2025 10:46:30 +0100 Subject: [PATCH 6/9] feat(cof_clubs): initial period in mass-add fix(cof_clubs): initial value for accounting period --- cof_clubs/forms.py | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/cof_clubs/forms.py b/cof_clubs/forms.py index 83d1840e..484c5a7e 100644 --- a/cof_clubs/forms.py +++ b/cof_clubs/forms.py @@ -55,6 +55,13 @@ class ClubBudgetLineCommonForm(Form): accounting_period = forms.ModelChoiceField( label="Exercice comptable", queryset=ClubBudgetAccountingPeriod.objects.filter(is_archived=False), + empty_label=None, ) label = forms.CharField(label="Libellé", max_length=1000) posted = forms.BooleanField(label="Transactions validées par la trez", initial=True) + + def __init__(self, *args, **kwargs): + super().__init__(*args, **kwargs) + self.fields["accounting_period"].initial = ( + ClubBudgetAccountingPeriod.objects.filter(is_archived=False).first() + ) From b45f5d568a21e1bc9e2711f1fd3a128986e804ba Mon Sep 17 00:00:00 2001 From: catvayor Date: Fri, 21 Mar 2025 11:06:47 +0100 Subject: [PATCH 7/9] feat(cof_clubs): club edit view --- cof_clubs/templates/cof_clubs/club_detail.html | 2 +- cof_clubs/urls.py | 5 +++-- cof_clubs/views.py | 8 ++++++++ 3 files changed, 12 insertions(+), 3 deletions(-) diff --git a/cof_clubs/templates/cof_clubs/club_detail.html b/cof_clubs/templates/cof_clubs/club_detail.html index c200c86b..c13cf789 100644 --- a/cof_clubs/templates/cof_clubs/club_detail.html +++ b/cof_clubs/templates/cof_clubs/club_detail.html @@ -5,7 +5,7 @@
-

{{ object.name }}

+

{{ object.name }} {% if user.profile.is_buro %}{% endif %}

Respos:
{% for r in object.respos.all %} diff --git a/cof_clubs/urls.py b/cof_clubs/urls.py index 202ac82c..fb54ab30 100644 --- a/cof_clubs/urls.py +++ b/cof_clubs/urls.py @@ -5,6 +5,9 @@ from . import views app_name = "cof_clubs" urlpatterns = [ path("", views.ClubListView.as_view(), name="club-list"), + path("club/add", views.ClubCreateView.as_view(), name="club-create"), + path("club/", views.ClubDetailView.as_view(), name="club-detail"), + path("club//edit", views.ClubEditView.as_view(), name="club-edit"), path( "acct-period/add", views.ClubBudgetAccountingPeriodCreateView.as_view(), @@ -15,8 +18,6 @@ urlpatterns = [ views.ClubBudgetAccountingPeriodUpdateView.as_view(), name="acct-period-update", ), - path("club/", views.ClubDetailView.as_view(), name="club-detail"), - path("club/add", views.ClubCreateView.as_view(), name="club-create"), path( "line///add", views.BudgetLineCreate.as_view(), diff --git a/cof_clubs/views.py b/cof_clubs/views.py index a9548b95..f44288c3 100644 --- a/cof_clubs/views.py +++ b/cof_clubs/views.py @@ -149,6 +149,14 @@ class ClubDetailView(AccessMixin, DetailView): return ctx +class ClubEditView(BuroRequiredMixin, UpdateView): + model = Club + fields = ["name", "description", "respos", "budget_managers"] + + def get_success_url(self): + return reverse("cof_clubs:club-detail", kwargs={"pk": self.object.id}) + + class BudgetLineCreate(BudgetLineAccessMixin, CreateView): model = ClubBudgetLine From 482649a6885ddd6b1312bc204f4d886e692db8f1 Mon Sep 17 00:00:00 2001 From: catvayor Date: Thu, 27 Mar 2025 17:53:42 +0100 Subject: [PATCH 8/9] feat(cof_clubs): widget for respo selection chore(nix-pkgs): update to solve django-bulma-forms bug --- cof_clubs/forms.py | 11 ++ .../cof_clubs/_widget_bigmultiselect.html | 154 ++++++++++++++++++ cof_clubs/views.py | 5 +- cof_clubs/widgets.py | 31 ++++ npins/sources.json | 8 +- requirements.txt | 1 + 6 files changed, 204 insertions(+), 6 deletions(-) create mode 100644 cof_clubs/templates/cof_clubs/_widget_bigmultiselect.html create mode 100644 cof_clubs/widgets.py diff --git a/cof_clubs/forms.py b/cof_clubs/forms.py index 484c5a7e..787eeaf4 100644 --- a/cof_clubs/forms.py +++ b/cof_clubs/forms.py @@ -5,6 +5,17 @@ from django.forms import Form, modelformset_factory from django.utils.translation import gettext_lazy as _ from .models import Club, ClubBudgetAccountingPeriod, ClubBudgetLine +from .widgets import BigMultiSelect + + +class ClubForm(forms.ModelForm): + class Meta: + model = Club + fields = ["name", "description", "respos", "budget_managers"] + widgets = { + "respos": BigMultiSelect, + "budget_managers": BigMultiSelect, + } class ClubBudgetLineForm(forms.ModelForm): diff --git a/cof_clubs/templates/cof_clubs/_widget_bigmultiselect.html b/cof_clubs/templates/cof_clubs/_widget_bigmultiselect.html new file mode 100644 index 00000000..aa2acd8a --- /dev/null +++ b/cof_clubs/templates/cof_clubs/_widget_bigmultiselect.html @@ -0,0 +1,154 @@ + + + + + + + + + + + + +
+ +
diff --git a/cof_clubs/views.py b/cof_clubs/views.py index f44288c3..09eb036a 100644 --- a/cof_clubs/views.py +++ b/cof_clubs/views.py @@ -15,13 +15,14 @@ from .forms import ( ClubBudgetLineForm, ClubBudgetLineFormSet, ClubBudgetLineFullForm, + ClubForm, ) from .models import Club, ClubBudgetAccountingPeriod, ClubBudgetLine class ClubCreateView(BuroRequiredMixin, SuccessMessageMixin, CreateView): model = Club - fields = ["name", "description", "respos", "budget_managers"] + form_class = ClubForm success_message = "Le club %(name)s a été créé avec succès" @@ -151,7 +152,7 @@ class ClubDetailView(AccessMixin, DetailView): class ClubEditView(BuroRequiredMixin, UpdateView): model = Club - fields = ["name", "description", "respos", "budget_managers"] + form_class = ClubForm def get_success_url(self): return reverse("cof_clubs:club-detail", kwargs={"pk": self.object.id}) diff --git a/cof_clubs/widgets.py b/cof_clubs/widgets.py new file mode 100644 index 00000000..532aded6 --- /dev/null +++ b/cof_clubs/widgets.py @@ -0,0 +1,31 @@ +from django.forms.widgets import Widget +from django.template.loader import render_to_string + + +class BigMultiSelect(Widget): + template_name = "BigMultiSelect" + + def __init__(self, attrs=None, choices=()): + super().__init__(attrs) + # choices can be any iterable, but we may need to render this widget + # multiple times. Thus, collapse it into a list so it can be consumed + # more than once. + self.choices = list(choices) + + def get_context(self, name, value, attrs): + ret = super().get_context(name, value, attrs) + ret["choices"] = self.choices + return ret + + def value_from_datadict(self, data, files, name): + return data.getlist(name) + + def render(self, name, value, attrs=None, renderer=None): + if value is None: + value = [] + attrs["value"] = value + final_attrs = self.build_attrs(self.attrs, attrs) + return render_to_string( + "cof_clubs/_widget_bigmultiselect.html", + self.get_context(name, value, attrs), + ) diff --git a/npins/sources.json b/npins/sources.json index 9ed77931..7f78c348 100644 --- a/npins/sources.json +++ b/npins/sources.json @@ -15,12 +15,12 @@ "type": "Git", "repository": { "type": "Git", - "url": "https://git.hubrecht.ovh/hubrecht/nix-pkgs" + "url": "https://git.hubrecht.ovh/hubrecht/nix-pkgs.git" }, - "branch": "main", - "revision": "ac4ff5a34789ae3398aff9501735b67b6a5a285a", + "branch": "dgnum", + "revision": "7a0e2e660b26ddd67bb8132beb6b13e3a69003a4", "url": null, - "hash": "16n37f74p6h30hhid98vab9w5b08xqj4qcshz2kc1jh67z5n49p6" + "hash": "0xx18q7rifpjq00mghqp280y61biyq5cvnyw6wbwa1zg4iywpv6n" }, "nixpkgs": { "type": "Channel", diff --git a/requirements.txt b/requirements.txt index 65d1d380..9413a7d0 100644 --- a/requirements.txt +++ b/requirements.txt @@ -5,6 +5,7 @@ channels==3.0.5 configparser==7.1.0 django-autocomplete-light==3.11.0 django-bootstrap-form==3.4 +django-bulma-forms==0.1.7 django-cas-ng==5.0.1 django-cors-headers==4.6.0 django-djconfig==0.11.0 From f6d45355c597ea4cc69606ea404f6b9cc063ebcc Mon Sep 17 00:00:00 2001 From: catvayor Date: Wed, 30 Apr 2025 16:54:16 +0200 Subject: [PATCH 9/9] chore(migrations): merge after rebase --- ...erge_0021_delete_club_0023_cofprofile_is_chef.py | 13 +++++++++++++ 1 file changed, 13 insertions(+) create mode 100644 gestioncof/migrations/0024_merge_0021_delete_club_0023_cofprofile_is_chef.py diff --git a/gestioncof/migrations/0024_merge_0021_delete_club_0023_cofprofile_is_chef.py b/gestioncof/migrations/0024_merge_0021_delete_club_0023_cofprofile_is_chef.py new file mode 100644 index 00000000..d7a5e4cf --- /dev/null +++ b/gestioncof/migrations/0024_merge_0021_delete_club_0023_cofprofile_is_chef.py @@ -0,0 +1,13 @@ +# Generated by Django 4.2.16 on 2025-04-30 14:53 + +from django.db import migrations + + +class Migration(migrations.Migration): + + dependencies = [ + ("gestioncof", "0021_delete_club"), + ("gestioncof", "0023_cofprofile_is_chef"), + ] + + operations = []