mirror of
				https://gitlab.crans.org/bde/nk20
				synced 2025-10-26 05:23:18 +01:00 
			
		
		
		
	Compare commits
	
		
			17 Commits
		
	
	
		
			delete_act
			...
			16cfaa809a
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
|  | 16cfaa809a | ||
|  | f2cd0b6d36 | ||
|  | a2e2ff5fa9 | ||
|  | 53d0480a12 | ||
|  | ff812a028c | ||
|  | 136f636fda | ||
|  | 5a8acbde00 | ||
|  | f60dc8cfa0 | ||
|  | 067dd6f9d1 | ||
|  | 7b1e32e514 | ||
|  | e88dbfd597 | ||
|  | 3d34270959 | ||
|  | 3bb99671ec | ||
|  | 0d69383dfd | ||
|  | 7b9ff119e8 | ||
|  | 108a56745c | ||
|  | 9643d7652b | 
| @@ -168,7 +168,8 @@ class BasicFoodCreateView(ProtectQuerysetMixin, ProtectedCreateView): | ||||
|     template_name = "food/food_update.html" | ||||
|  | ||||
|     def get_sample_object(self): | ||||
|         return BasicFood( | ||||
|         # We choose a club which may work or BDE else | ||||
|         food = BasicFood( | ||||
|             name="", | ||||
|             owner_id=1, | ||||
|             expiry_date=timezone.now(), | ||||
| @@ -177,6 +178,14 @@ class BasicFoodCreateView(ProtectQuerysetMixin, ProtectedCreateView): | ||||
|             date_type='DLC', | ||||
|         ) | ||||
|  | ||||
|         for membership in self.request.user.memberships.all(): | ||||
|             club_id = membership.club.id | ||||
|             food.owner_id = club_id | ||||
|             if PermissionBackend.check_perm(self.request, "food.add_basicfood", food): | ||||
|                 return food | ||||
|  | ||||
|         return food | ||||
|  | ||||
|     @transaction.atomic | ||||
|     def form_valid(self, form): | ||||
|         if QRCode.objects.filter(qr_code_number=self.kwargs['slug']).count() > 0: | ||||
| @@ -227,13 +236,22 @@ class TransformedFoodCreateView(ProtectQuerysetMixin, ProtectedCreateView): | ||||
|     template_name = "food/food_update.html" | ||||
|  | ||||
|     def get_sample_object(self): | ||||
|         return TransformedFood( | ||||
|         # We choose a club which may work or BDE else | ||||
|         food = TransformedFood( | ||||
|             name="", | ||||
|             owner_id=1, | ||||
|             expiry_date=timezone.now(), | ||||
|             is_ready=True, | ||||
|         ) | ||||
|  | ||||
|         for membership in self.request.user.memberships.all(): | ||||
|             club_id = membership.club.id | ||||
|             food.owner_id = club_id | ||||
|             if PermissionBackend.check_perm(self.request, "food.add_transformedfood", food): | ||||
|                 return food | ||||
|  | ||||
|         return food | ||||
|  | ||||
|     @transaction.atomic | ||||
|     def form_valid(self, form): | ||||
|         form.instance.expiry_date = timezone.now() + timedelta(days=3) | ||||
| @@ -245,10 +263,10 @@ class TransformedFoodCreateView(ProtectQuerysetMixin, ProtectedCreateView): | ||||
|         return reverse_lazy('food:transformedfood_view', kwargs={"pk": self.object.pk}) | ||||
|  | ||||
|  | ||||
| MAX_FORMS = 10 | ||||
| MAX_FORMS = 100 | ||||
|  | ||||
|  | ||||
| class ManageIngredientsView(ProtectQuerysetMixin, LoginRequiredMixin, UpdateView): | ||||
| class ManageIngredientsView(LoginRequiredMixin, UpdateView): | ||||
|     """ | ||||
|     A view to manage ingredient for a transformed food | ||||
|     """ | ||||
| @@ -279,6 +297,14 @@ class ManageIngredientsView(ProtectQuerysetMixin, LoginRequiredMixin, UpdateView | ||||
|                     ingredient.end_of_life = _('Fully used in {meal}'.format( | ||||
|                         meal=self.object.name)) | ||||
|                     ingredient.save() | ||||
|         # We recalculate new expiry date and allergens | ||||
|         self.object.expiry_date = self.object.creation_date + self.object.shelf_life | ||||
|         self.object.allergens.clear() | ||||
|  | ||||
|         for ingredient in self.object.ingredients.iterator(): | ||||
|             if not (ingredient.polymorphic_ctype.model == 'basicfood' and ingredient.date_type == 'DDM'): | ||||
|                 self.object.expiry_date = min(self.object.expiry_date, ingredient.expiry_date) | ||||
|             self.object.allergens.set(self.object.allergens.union(ingredient.allergens.all())) | ||||
|  | ||||
|         self.object.save(old_ingredients=old_ingredients, old_allergens=old_allergens) | ||||
|         return HttpResponseRedirect(self.get_success_url()) | ||||
|   | ||||
							
								
								
									
										46
									
								
								apps/member/migrations/0014_create_bda.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										46
									
								
								apps/member/migrations/0014_create_bda.py
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,46 @@ | ||||
| from django.db import migrations | ||||
|  | ||||
| def create_bda(apps, schema_editor): | ||||
|     """ | ||||
|     The club BDA is now pre-injected. | ||||
|     """ | ||||
|     Club = apps.get_model("member", "club") | ||||
|     NoteClub = apps.get_model("note", "noteclub") | ||||
|     Alias = apps.get_model("note", "alias") | ||||
|     ContentType = apps.get_model('contenttypes', 'ContentType') | ||||
|     polymorphic_ctype_id = ContentType.objects.get_for_model(NoteClub).id | ||||
|      | ||||
|     Club.objects.get_or_create( | ||||
|         id=10, | ||||
|         name="BDA", | ||||
|         email="bda.ensparissaclay@gmail.com", | ||||
|         require_memberships=True, | ||||
|         membership_fee_paid=750, | ||||
|         membership_fee_unpaid=750, | ||||
|         membership_duration=396, | ||||
|         membership_start="2024-08-01", | ||||
|         membership_end="2025-09-30", | ||||
|     ) | ||||
|     NoteClub.objects.get_or_create( | ||||
|         id=1937, | ||||
|         club_id=10, | ||||
|         polymorphic_ctype_id=polymorphic_ctype_id, | ||||
|     ) | ||||
|     Alias.objects.get_or_create( | ||||
|         id=1937, | ||||
|         note_id=1937, | ||||
|         name="BDA", | ||||
|         normalized_name="bda", | ||||
|     ) | ||||
|  | ||||
|  | ||||
| class Migration(migrations.Migration): | ||||
|  | ||||
|     dependencies = [ | ||||
|         ('member', '0013_auto_20240801_1436'), | ||||
|     ] | ||||
|      | ||||
|     operations = [ | ||||
|         migrations.RunPython(create_bda), | ||||
|     ] | ||||
|  | ||||
| @@ -3998,6 +3998,54 @@ | ||||
|             "description": "Créer une transaction de ou vers la note d'un club tant que la source reste au dessus de -50 €" | ||||
|         } | ||||
|     }, | ||||
|     { | ||||
|         "model": "permission.permission", | ||||
|         "pk": 271, | ||||
|         "fields": { | ||||
|             "model": [ | ||||
|                 "wei", | ||||
|                 "bus" | ||||
|             ], | ||||
|             "query": "{\"wei\": [\"club\"]}", | ||||
|             "type": "change", | ||||
|             "mask": 3, | ||||
|             "field": "", | ||||
|             "permanent": false, | ||||
|             "description": "Modifier n'importe quel bus du wei" | ||||
|         } | ||||
|     }, | ||||
|     { | ||||
|         "model": "permission.permission", | ||||
|         "pk": 272, | ||||
|         "fields": { | ||||
|             "model": [ | ||||
|                 "wei", | ||||
|                 "bus" | ||||
|             ], | ||||
|             "query": "{\"wei\": [\"club\"]}", | ||||
|             "type": "view", | ||||
|             "mask": 3, | ||||
|             "field": "", | ||||
|             "permanent": false, | ||||
|             "description": "Voir tous les bus du wei" | ||||
|         } | ||||
|     }, | ||||
|     { | ||||
|         "model": "permission.permission", | ||||
|         "pk": 273, | ||||
|         "fields": { | ||||
|             "model": [ | ||||
|                 "wei", | ||||
|                 "busteam" | ||||
|             ], | ||||
|             "query": "{\"bus__wei\": [\"club\"], \"bus__wei__membership_end__gte\": [\"today\"]}", | ||||
|             "type": "view", | ||||
|             "mask": 3, | ||||
|             "field": "", | ||||
|             "permanent": false, | ||||
|             "description": "Voir toutes les équipes WEI" | ||||
|         } | ||||
|     }, | ||||
|     { | ||||
|         "model": "permission.role", | ||||
|         "pk": 1, | ||||
| @@ -4091,8 +4139,8 @@ | ||||
|                 158, | ||||
|                 159, | ||||
|                 160, | ||||
| 		212, | ||||
| 		222 | ||||
|                 212, | ||||
|                 222 | ||||
|             ] | ||||
|         } | ||||
|     }, | ||||
| @@ -4133,14 +4181,14 @@ | ||||
|                 50, | ||||
|                 141, | ||||
|                 169, | ||||
| 		217, | ||||
| 		218, | ||||
| 		219, | ||||
| 		220, | ||||
| 		221, | ||||
| 		247, | ||||
| 		258, | ||||
| 		259 | ||||
|                 217, | ||||
|                 218, | ||||
|                 219, | ||||
|                 220, | ||||
|                 221, | ||||
|                 247, | ||||
|                 258, | ||||
|                 259 | ||||
|             ] | ||||
|         } | ||||
|     }, | ||||
| @@ -4152,8 +4200,8 @@ | ||||
|             "name": "Pr\u00e9sident\u22c5e de club", | ||||
|             "permissions": [ | ||||
|                 62, | ||||
|                 142, | ||||
|                 135 | ||||
|                 135, | ||||
|                 142 | ||||
|             ] | ||||
|         } | ||||
|     }, | ||||
| @@ -4382,7 +4430,10 @@ | ||||
|                 112, | ||||
|                 113, | ||||
|                 128, | ||||
|                 130 | ||||
|                 130, | ||||
|                 271, | ||||
|                 272, | ||||
|                 273 | ||||
|             ] | ||||
|         } | ||||
|     }, | ||||
| @@ -4538,8 +4589,8 @@ | ||||
|             "name": "GC anti-VSS", | ||||
|             "permissions": [ | ||||
|                 42, | ||||
| 		135, | ||||
| 		150, | ||||
|                 135, | ||||
|                 150, | ||||
|                 163, | ||||
|                 164 | ||||
|             ] | ||||
| @@ -4555,10 +4606,137 @@ | ||||
|                 137, | ||||
|                 211, | ||||
|                 212, | ||||
| 		213, | ||||
| 		214, | ||||
| 		215, | ||||
| 		216 | ||||
|                 213, | ||||
|                 214, | ||||
|                 215, | ||||
|                 216 | ||||
|             ] | ||||
|         } | ||||
|     },   | ||||
|     { | ||||
|         "model": "permission.role", | ||||
|         "pk": 23, | ||||
|             "fields": { | ||||
|             "for_club": 2, | ||||
|             "name": "Darbonne", | ||||
|             "permissions": [ | ||||
|                 30, | ||||
|                 31, | ||||
|                 32 | ||||
|             ] | ||||
|         } | ||||
|     },  | ||||
|     { | ||||
|         "model": "permission.role", | ||||
|         "pk": 24, | ||||
|             "fields": { | ||||
|             "for_club": null, | ||||
|             "name": "Staffeur⋅euse (S&L,Respo Tech,...)", | ||||
|             "permissions": [] | ||||
|         } | ||||
|     },  | ||||
|     { | ||||
|         "model": "permission.role", | ||||
|         "pk": 25, | ||||
|             "fields": { | ||||
|             "for_club": null, | ||||
|             "name": "Référent⋅e Bus", | ||||
|             "permissions": [ | ||||
|                 22, | ||||
|                 84, | ||||
|                 115, | ||||
|                 117, | ||||
|                 118, | ||||
|                 119, | ||||
|                 120, | ||||
|                 121, | ||||
|                 122 | ||||
|             ] | ||||
|         } | ||||
|     },  | ||||
|     { | ||||
|         "model": "permission.role", | ||||
|         "pk": 28, | ||||
|             "fields": { | ||||
|             "for_club": 10, | ||||
|             "name": "Trésorièr⸱e BDA", | ||||
|             "permissions": [ | ||||
|                 55, | ||||
|                 56, | ||||
|                 57, | ||||
|                 58, | ||||
|                 135, | ||||
|                 143, | ||||
|                 176, | ||||
|                 177, | ||||
|                 178, | ||||
|                 243, | ||||
|                 260, | ||||
|                 261, | ||||
|                 262, | ||||
|                 263, | ||||
|                 264, | ||||
|                 265, | ||||
|                 266, | ||||
|                 267, | ||||
|                 268, | ||||
|                 269 | ||||
|             ] | ||||
|         } | ||||
|     },  | ||||
|     { | ||||
|         "model": "permission.role", | ||||
|         "pk": 30, | ||||
|             "fields": { | ||||
|             "for_club": 10, | ||||
|             "name": "Respo sorties", | ||||
|             "permissions": [ | ||||
|                 49,  | ||||
|                 62,  | ||||
|                 141,  | ||||
|                 241,  | ||||
|                 242,  | ||||
|                 243 | ||||
|             ] | ||||
|         } | ||||
|     },  | ||||
|     { | ||||
|         "model": "permission.role", | ||||
|         "pk": 31, | ||||
|             "fields": { | ||||
|             "for_club": 1, | ||||
|             "name": "Respo comm", | ||||
|             "permissions": [ | ||||
|                 135, | ||||
|                 244 | ||||
|             ] | ||||
|         } | ||||
|     },  | ||||
|     { | ||||
|         "model": "permission.role", | ||||
|         "pk": 32, | ||||
|             "fields": { | ||||
|             "for_club": 10, | ||||
|             "name": "Respo comm Art", | ||||
|             "permissions": [ | ||||
|                 135, | ||||
|                 245 | ||||
|             ] | ||||
|         } | ||||
|     },  | ||||
|     { | ||||
|         "model": "permission.role", | ||||
|         "pk": 33, | ||||
|             "fields": { | ||||
|             "for_club": 10, | ||||
|             "name": "Respo Jam", | ||||
|             "permissions": [ | ||||
|                 247,  | ||||
|                 250,  | ||||
|                 251,  | ||||
|                 252,  | ||||
|                 253,  | ||||
|                 254 | ||||
|             ] | ||||
|         } | ||||
|     },  | ||||
| @@ -4596,5 +4774,15 @@ | ||||
|         "model": "wei.weirole", | ||||
|         "pk": 18, | ||||
|         "fields": {} | ||||
|     }, | ||||
|     { | ||||
|         "model": "wei.weirole", | ||||
|         "pk": 24, | ||||
|         "fields": {} | ||||
|     }, | ||||
|     { | ||||
|         "model": "wei.weirole", | ||||
|         "pk": 25, | ||||
|         "fields": {} | ||||
|     } | ||||
| ] | ||||
|   | ||||
| @@ -39,7 +39,9 @@ class WEIRegistrationForm(forms.ModelForm): | ||||
|  | ||||
|     class Meta: | ||||
|         model = WEIRegistration | ||||
|         exclude = ('wei', 'clothing_cut') | ||||
|         fields = ['user', 'soge_credit', 'birth_date', 'gender', 'clothing_size',  | ||||
|                 'health_issues', 'emergency_contact_name', 'emergency_contact_phone', 'first_year', | ||||
|                 'information_json'] | ||||
|         widgets = { | ||||
|             "user": Autocomplete( | ||||
|                 User, | ||||
| @@ -50,7 +52,7 @@ class WEIRegistrationForm(forms.ModelForm): | ||||
|                 }, | ||||
|             ), | ||||
|             "birth_date": DatePickerInput(options={'minDate': '1900-01-01', | ||||
|                                                    'maxDate': '2100-01-01'}), | ||||
|                                                 'maxDate': '2100-01-01'}), | ||||
|         } | ||||
|  | ||||
|  | ||||
| @@ -81,11 +83,6 @@ class WEIChooseBusForm(forms.Form): | ||||
|  | ||||
|  | ||||
| class WEIMembershipForm(forms.ModelForm): | ||||
|     caution_check = forms.BooleanField( | ||||
|         required=False, | ||||
|         label=_("Caution check given"), | ||||
|     ) | ||||
|  | ||||
|     roles = forms.ModelMultipleChoiceField( | ||||
|         queryset=WEIRole.objects, | ||||
|         label=_("WEI Roles"), | ||||
| @@ -194,3 +191,4 @@ class BusTeamForm(forms.ModelForm): | ||||
|             ), | ||||
|             "color": ColorWidget(), | ||||
|         } | ||||
|         # "color": ColorWidget(), | ||||
|   | ||||
							
								
								
									
										18
									
								
								apps/wei/migrations/0011_alter_weiclub_year.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										18
									
								
								apps/wei/migrations/0011_alter_weiclub_year.py
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,18 @@ | ||||
| # Generated by Django 4.2.21 on 2025-05-25 12:23 | ||||
|  | ||||
| from django.db import migrations, models | ||||
|  | ||||
|  | ||||
| class Migration(migrations.Migration): | ||||
|  | ||||
|     dependencies = [ | ||||
|         ('wei', '0010_remove_weiregistration_specific_diet'), | ||||
|     ] | ||||
|  | ||||
|     operations = [ | ||||
|         migrations.AlterField( | ||||
|             model_name='weiclub', | ||||
|             name='year', | ||||
|             field=models.PositiveIntegerField(default=2025, unique=True, verbose_name='year'), | ||||
|         ), | ||||
|     ] | ||||
| @@ -98,7 +98,7 @@ class WEIRegistrationTable(tables.Table): | ||||
|         if not hasperm: | ||||
|             return format_html("<span class='no-perm'></span>") | ||||
|  | ||||
|         url = reverse_lazy('wei:validate_registration', args=(record.pk,)) | ||||
|         url = reverse_lazy('wei:wei_update_registration', args=(record.pk,)) + '?validate=true' | ||||
|         text = _('Validate') | ||||
|         if record.fee > record.user.note.balance and not record.soge_credit: | ||||
|             btn_class = 'btn-secondary' | ||||
|   | ||||
| @@ -18,6 +18,8 @@ SPDX-License-Identifier: GPL-3.0-or-later | ||||
|     <div class="card-footer text-center"> | ||||
|         <a class="btn btn-primary btn-sm my-1" href="{% url 'wei:update_bus' pk=bus.pk %}" | ||||
|             data-turbolinks="false">{% trans "Edit" %}</a> | ||||
|         <a class="btn btn-primary btn-sm my-1" href="{% url 'wei:manage_bus' pk=bus.pk %}" | ||||
|             data-turbolinks="false">{% trans "View" %}</a> | ||||
|         <a class="btn btn-primary btn-sm my-1" href="{% url 'wei:add_team' pk=bus.pk %}" | ||||
|             data-turbolinks="false">{% trans "Add team" %}</a> | ||||
|     </div> | ||||
|   | ||||
| @@ -13,9 +13,17 @@ SPDX-License-Identifier: GPL-3.0-or-later | ||||
|     <div class="card-body"> | ||||
|         <form method="post"> | ||||
|             {% csrf_token %} | ||||
|             {{ form.media }}  | ||||
|             {{ form|crispy }} | ||||
|             <button class="btn btn-primary" type="submit">{% trans "Submit" %}</button> | ||||
|         </form> | ||||
|     </div> | ||||
| </div> | ||||
| <script> | ||||
|     document.addEventListener("DOMContentLoaded", function () { | ||||
|         if (window.jscolor && jscolor.install) { | ||||
|             jscolor.install(); | ||||
|         } | ||||
|     }); | ||||
| </script> | ||||
| {% endblock %} | ||||
| @@ -8,18 +8,20 @@ from datetime import date, timedelta | ||||
| from tempfile import mkdtemp | ||||
|  | ||||
| from django.conf import settings | ||||
| from django.contrib import messages | ||||
| from django.contrib.auth.mixins import LoginRequiredMixin | ||||
| from django.contrib.auth.models import User | ||||
| from django.core.exceptions import PermissionDenied | ||||
| from django.db import transaction | ||||
| from django.db.models import Q, Count | ||||
| from django.db.models.functions.text import Lower | ||||
| from django import forms | ||||
| from django.http import HttpResponse, Http404 | ||||
| from django.shortcuts import redirect | ||||
| from django.template.loader import render_to_string | ||||
| from django.urls import reverse_lazy | ||||
| from django.views import View | ||||
| from django.views.generic import DetailView, UpdateView, RedirectView, TemplateView | ||||
| from django.views.generic import DetailView, UpdateView, RedirectView, TemplateView, CreateView | ||||
| from django.utils.translation import gettext_lazy as _ | ||||
| from django.views.generic.edit import BaseFormView, DeleteView | ||||
| from django_tables2 import SingleTableView, MultiTableMixin | ||||
| @@ -37,6 +39,7 @@ from .forms import WEIForm, WEIRegistrationForm, BusForm, BusTeamForm, WEIMember | ||||
|     WEIMembershipForm, CurrentSurvey | ||||
| from .tables import BusRepartitionTable, BusTable, BusTeamTable, WEITable, WEIRegistrationTable, \ | ||||
|     WEIRegistration1ATable, WEIMembershipTable | ||||
| from .forms.surveys import CurrentSurvey | ||||
|  | ||||
|  | ||||
| class CurrentWEIDetailView(LoginRequiredMixin, RedirectView): | ||||
| @@ -441,6 +444,13 @@ class BusTeamCreateView(ProtectQuerysetMixin, ProtectedCreateView): | ||||
|         self.object.refresh_from_db() | ||||
|         return reverse_lazy("wei:manage_bus_team", kwargs={"pk": self.object.pk}) | ||||
|      | ||||
|     def get_template_names(self): | ||||
|         names = super().get_template_names() | ||||
|         return names | ||||
|      | ||||
|  | ||||
|  | ||||
|  | ||||
|  | ||||
| class BusTeamUpdateView(ProtectQuerysetMixin, LoginRequiredMixin, UpdateView): | ||||
|     """ | ||||
| @@ -473,6 +483,13 @@ class BusTeamUpdateView(ProtectQuerysetMixin, LoginRequiredMixin, UpdateView): | ||||
|         self.object.refresh_from_db() | ||||
|         return reverse_lazy("wei:manage_bus_team", kwargs={"pk": self.object.pk}) | ||||
|      | ||||
|     def get_template_names(self): | ||||
|         names = super().get_template_names() | ||||
|         return names | ||||
|      | ||||
|  | ||||
|  | ||||
|  | ||||
|  | ||||
| class BusTeamManageView(ProtectQuerysetMixin, LoginRequiredMixin, DetailView): | ||||
|     """ | ||||
| @@ -546,9 +563,15 @@ class WEIRegister1AView(ProtectQuerysetMixin, ProtectedCreateView): | ||||
|     def get_form(self, form_class=None): | ||||
|         form = super().get_form(form_class) | ||||
|         form.fields["user"].initial = self.request.user | ||||
|         del form.fields["first_year"] | ||||
|         del form.fields["caution_check"] | ||||
|         del form.fields["information_json"] | ||||
|          | ||||
|         # Cacher les champs pendant l'inscription initiale | ||||
|         if "first_year" in form.fields: | ||||
|             del form.fields["first_year"] | ||||
|         if "caution_check" in form.fields: | ||||
|             del form.fields["caution_check"] | ||||
|         if "information_json" in form.fields: | ||||
|             del form.fields["information_json"] | ||||
|              | ||||
|         return form | ||||
|  | ||||
|     @transaction.atomic | ||||
| @@ -644,9 +667,13 @@ class WEIRegister2AView(ProtectQuerysetMixin, ProtectedCreateView): | ||||
|             form.fields["soge_credit"].disabled = True | ||||
|             form.fields["soge_credit"].help_text = _("You already opened an account in the Société générale.") | ||||
|  | ||||
|         del form.fields["caution_check"] | ||||
|         del form.fields["first_year"] | ||||
|         del form.fields["information_json"] | ||||
|         # Cacher les champs pendant l'inscription initiale | ||||
|         if "first_year" in form.fields: | ||||
|             del form.fields["first_year"] | ||||
|         if "caution_check" in form.fields: | ||||
|             del form.fields["caution_check"] | ||||
|         if "information_json" in form.fields: | ||||
|             del form.fields["information_json"] | ||||
|  | ||||
|         return form | ||||
|  | ||||
| @@ -702,11 +729,15 @@ class WEIUpdateRegistrationView(ProtectQuerysetMixin, LoginRequiredMixin, Update | ||||
|         # We can't update a registration once the WEI is started and before the membership start date | ||||
|         if today >= wei.date_start or today < wei.membership_start: | ||||
|             return redirect(reverse_lazy('wei:wei_closed', args=(wei.pk,))) | ||||
|         # Store the validate parameter in the view's state | ||||
|         self.should_validate = request.GET.get('validate', False) | ||||
|         return super().dispatch(request, *args, **kwargs) | ||||
|  | ||||
|     def get_context_data(self, **kwargs): | ||||
|         context = super().get_context_data(**kwargs) | ||||
|         context["club"] = self.object.wei | ||||
|         # Pass the validate parameter to the template | ||||
|         context["should_validate"] = self.should_validate | ||||
|  | ||||
|         if self.object.is_validated: | ||||
|             membership_form = self.get_membership_form(instance=self.object.membership, | ||||
| @@ -740,6 +771,9 @@ class WEIUpdateRegistrationView(ProtectQuerysetMixin, LoginRequiredMixin, Update | ||||
|         # The auto-json-format may cause issues with the default field remove | ||||
|         if not PermissionBackend.check_perm(self.request, 'wei.change_weiregistration_information_json', self.object): | ||||
|             del form.fields["information_json"] | ||||
|         # Masquer le champ caution_check pour tout le monde dans le formulaire de modification | ||||
|         if "caution_check" in form.fields: | ||||
|             del form.fields["caution_check"] | ||||
|         return form | ||||
|  | ||||
|     def get_membership_form(self, data=None, instance=None): | ||||
| @@ -759,10 +793,30 @@ class WEIUpdateRegistrationView(ProtectQuerysetMixin, LoginRequiredMixin, Update | ||||
|     def form_valid(self, form): | ||||
|         # If the membership is already validated, then we update the bus and the team (and the roles) | ||||
|         if form.instance.is_validated: | ||||
|             membership_form = self.get_membership_form(self.request.POST, form.instance.membership) | ||||
|             if not membership_form.is_valid(): | ||||
|             try: | ||||
|                 membership = form.instance.membership | ||||
|                 if membership is None: | ||||
|                     raise ValueError(_("No membership found for this registration")) | ||||
|                  | ||||
|                 membership_form = self.get_membership_form(self.request.POST, instance=membership) | ||||
|                 if not membership_form.is_valid(): | ||||
|                     return self.form_invalid(form) | ||||
|                  | ||||
|                 # Vérifier que l'utilisateur a la permission de modifier le membership | ||||
|                 # On vérifie d'abord si l'utilisateur a la permission générale de modification | ||||
|                 if not self.request.user.has_perm("wei.change_weimembership"): | ||||
|                     raise PermissionDenied(_("You don't have the permission to update memberships")) | ||||
|                  | ||||
|                 # On vérifie ensuite les permissions spécifiques pour chaque champ modifié | ||||
|                 for field_name in membership_form.changed_data: | ||||
|                     perm = f"wei.change_weimembership_{field_name}" | ||||
|                     if not self.request.user.has_perm(perm): | ||||
|                         raise PermissionDenied(_("You don't have the permission to update the field %(field)s") % {'field': field_name}) | ||||
|                  | ||||
|                 membership_form.save() | ||||
|             except (WEIMembership.DoesNotExist, ValueError, PermissionDenied) as e: | ||||
|                 form.add_error(None, str(e)) | ||||
|                 return self.form_invalid(form) | ||||
|             membership_form.save() | ||||
|         # If it is not validated and if this is an old member, then we update the choices | ||||
|         elif not form.instance.first_year and PermissionBackend.check_perm( | ||||
|                 self.request, "wei.change_weiregistration_information_json", self.object): | ||||
| @@ -787,14 +841,8 @@ class WEIUpdateRegistrationView(ProtectQuerysetMixin, LoginRequiredMixin, Update | ||||
|             survey = CurrentSurvey(self.object) | ||||
|             if not survey.is_complete(): | ||||
|                 return reverse_lazy("wei:wei_survey", kwargs={"pk": self.object.pk}) | ||||
|         if PermissionBackend.check_perm(self.request, "wei.add_weimembership", WEIMembership( | ||||
|             club=self.object.wei, | ||||
|             user=self.object.user, | ||||
|             date_start=date.today(), | ||||
|             date_end=date.today(), | ||||
|             fee=0, | ||||
|             registration=self.object, | ||||
|         )): | ||||
|         # On redirige vers la validation uniquement si c'est explicitement demandé (et stocké dans la vue) | ||||
|         if self.should_validate and self.request.user.has_perm("wei.add_weimembership"): | ||||
|             return reverse_lazy("wei:validate_registration", kwargs={"pk": self.object.pk}) | ||||
|         return reverse_lazy("wei:wei_detail", kwargs={"pk": self.object.wei.pk}) | ||||
|  | ||||
| @@ -828,26 +876,21 @@ class WEIDeleteRegistrationView(ProtectQuerysetMixin, LoginRequiredMixin, Delete | ||||
|         return reverse_lazy('wei:wei_detail', args=(self.object.wei.pk,)) | ||||
|  | ||||
|  | ||||
| class WEIValidateRegistrationView(ProtectQuerysetMixin, ProtectedCreateView): | ||||
| class WEIValidateRegistrationView(LoginRequiredMixin, CreateView): | ||||
|     """ | ||||
|     Validate WEI Registration | ||||
|     """ | ||||
|     model = WEIMembership | ||||
|     extra_context = {"title": _("Validate WEI registration")} | ||||
|  | ||||
|     def get_sample_object(self): | ||||
|         registration = WEIRegistration.objects.get(pk=self.kwargs["pk"]) | ||||
|         return WEIMembership( | ||||
|             club=registration.wei, | ||||
|             user=registration.user, | ||||
|             date_start=date.today(), | ||||
|             date_end=date.today() + timedelta(days=1), | ||||
|             fee=0, | ||||
|             registration=registration, | ||||
|         ) | ||||
|  | ||||
|     def dispatch(self, request, *args, **kwargs): | ||||
|         wei = WEIRegistration.objects.get(pk=self.kwargs["pk"]).wei | ||||
|         # Vérifier d'abord si l'utilisateur a la permission générale | ||||
|         if not request.user.has_perm("wei.add_weimembership"): | ||||
|             raise PermissionDenied(_("You don't have the permission to validate registrations")) | ||||
|              | ||||
|         registration = WEIRegistration.objects.get(pk=self.kwargs["pk"]) | ||||
|          | ||||
|         wei = registration.wei | ||||
|         today = date.today() | ||||
|         # We can't validate anyone once the WEI is started and before the membership start date | ||||
|         if today >= wei.date_start or today < wei.membership_start: | ||||
| @@ -900,8 +943,14 @@ class WEIValidateRegistrationView(ProtectQuerysetMixin, ProtectedCreateView): | ||||
|         form.fields["last_name"].initial = registration.user.last_name | ||||
|         form.fields["first_name"].initial = registration.user.first_name | ||||
|  | ||||
|         if "caution_check" in form.fields: | ||||
|             form.fields["caution_check"].initial = registration.caution_check | ||||
|         # Ajouter le champ caution_check uniquement pour les non-première année et le rendre obligatoire | ||||
|         if not registration.first_year: | ||||
|             form.fields["caution_check"] = forms.BooleanField( | ||||
|                 required=True, | ||||
|                 initial=registration.caution_check, | ||||
|                 label=_("Caution check given"), | ||||
|                 help_text=_("Please make sure the check is given before validating the registration") | ||||
|             ) | ||||
|  | ||||
|         if registration.soge_credit: | ||||
|             form.fields["credit_type"].disabled = True | ||||
| @@ -1289,8 +1338,22 @@ class WEIAttributeBus1ANextView(LoginRequiredMixin, RedirectView): | ||||
|         if not wei.exists(): | ||||
|             raise Http404 | ||||
|         wei = wei.get() | ||||
|         qs = WEIRegistration.objects.filter(wei=wei, membership__isnull=False, membership__bus__isnull=True) | ||||
|         qs = qs.filter(information_json__contains='selected_bus_pk')  # not perfect, but works... | ||||
|         if qs.exists(): | ||||
|             return reverse_lazy('wei:wei_bus_1A', args=(qs.first().pk, )) | ||||
|         return reverse_lazy('wei:wei_1A_list', args=(wei.pk, )) | ||||
|          | ||||
|         # On cherche d'abord les 1A qui ont une inscription validée (membership) mais pas de bus | ||||
|         qs = WEIRegistration.objects.filter( | ||||
|             wei=wei, | ||||
|             first_year=True, | ||||
|             membership__isnull=False, | ||||
|             membership__bus__isnull=True | ||||
|         ) | ||||
|          | ||||
|         # Parmi eux, on prend ceux qui ont répondu au questionnaire (ont un bus préféré) | ||||
|         qs = qs.filter(information_json__contains='selected_bus_pk') | ||||
|          | ||||
|         if not qs.exists(): | ||||
|             # Si on ne trouve personne, on affiche un message et on retourne à la liste | ||||
|             messages.info(self.request, _("No first year student without a bus found. Either all of them have a bus, or none has filled the survey yet.")) | ||||
|             return reverse_lazy('wei:wei_1A_list', args=(wei.pk,)) | ||||
|              | ||||
|         # On redirige vers la page d'attribution pour le premier étudiant trouvé | ||||
|         return reverse_lazy('wei:wei_bus_1A', args=(qs.first().pk,)) | ||||
|   | ||||
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							| @@ -63,8 +63,16 @@ class ColorWidget(Widget): | ||||
|     def format_value(self, value): | ||||
|         if value is None: | ||||
|             value = 0xFFFFFF | ||||
|         return "#{:06X}".format(value) | ||||
|         if isinstance(value, str): | ||||
|             return value  # Assume it's already a hex string like "#FFAA33" | ||||
|         try: | ||||
|             return "#{:06X}".format(value) | ||||
|         except Exception: | ||||
|             return "#FFFFFF" | ||||
|  | ||||
|  | ||||
|     def value_from_datadict(self, data, files, name): | ||||
|         val = super().value_from_datadict(data, files, name) | ||||
|         return int(val[1:], 16) | ||||
|         if val: | ||||
|             return int(val[1:], 16) | ||||
|         return None | ||||
							
								
								
									
										5
									
								
								note_kfet/templates/colorfield/color.html
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										5
									
								
								note_kfet/templates/colorfield/color.html
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,5 @@ | ||||
| <input type="text" | ||||
|        name="{{ widget.name }}" | ||||
|        value="{{ widget.value }}" | ||||
|        class="jscolor" | ||||
|        {% include "django/forms/widgets/attrs.html" %}> | ||||
		Reference in New Issue
	
	Block a user