diff --git a/apps/food/views.py b/apps/food/views.py index 4af4020b..2ee8c998 100644 --- a/apps/food/views.py +++ b/apps/food/views.py @@ -74,11 +74,15 @@ class FoodListView(ProtectQuerysetMixin, LoginRequiredMixin, MultiTableMixin, Li search_table = qs.filter(PermissionBackend.filter_queryset(self.request, Food, 'view')) # table open - open_table = self.get_queryset().order_by('expiry_date').filter( + open_table = self.get_queryset().filter( Q(polymorphic_ctype__model='transformedfood') | Q(polymorphic_ctype__model='basicfood', basicfood__date_type='DLC')).filter( expiry_date__lt=timezone.now(), end_of_life='').filter( PermissionBackend.filter_queryset(self.request, Food, 'view')) + open_table = open_table.union(self.get_queryset().filter( + Q(end_of_life='', order__iexact='open') + ).filter( + PermissionBackend.filter_queryset(self.request, Food, 'view'))).order_by('expiry_date') # table served served_table = self.get_queryset().order_by('-pk').filter( end_of_life='', is_ready=True).exclude( diff --git a/apps/member/models.py b/apps/member/models.py index ea859ea5..e08d4b59 100644 --- a/apps/member/models.py +++ b/apps/member/models.py @@ -417,7 +417,7 @@ class Membership(models.Model): A membership is valid if today is between the start and the end date. """ if self.date_end is not None: - return self.date_start.toordinal() <= datetime.datetime.now().toordinal() < self.date_end.toordinal() + return self.date_start.toordinal() <= datetime.datetime.now().toordinal() <= self.date_end.toordinal() else: return self.date_start.toordinal() <= datetime.datetime.now().toordinal() diff --git a/apps/note/static/note/js/consos.js b/apps/note/static/note/js/consos.js index d08d93bd..99bdf610 100644 --- a/apps/note/static/note/js/consos.js +++ b/apps/note/static/note/js/consos.js @@ -228,7 +228,7 @@ function consume (source, source_alias, dest, quantity, amount, reason, type, ca addMsg(interpolate(gettext('Warning, the transaction from the note %s succeed, ' + 'but the emitter note %s is negative.'), [source_alias, source_alias]), 'warning', 30000) } - if (source.membership && source.membership.date_end < new Date().toISOString()) { + if (source.membership && source.membership.date_end <= new Date().toISOString()) { addMsg(interpolate(gettext('Warning, the emitter note %s is no more a BDE member.'), [source_alias]), 'danger', 30000) } diff --git a/apps/note/static/note/js/transfer.js b/apps/note/static/note/js/transfer.js index ce6ff6ff..1c8797f4 100644 --- a/apps/note/static/note/js/transfer.js +++ b/apps/note/static/note/js/transfer.js @@ -310,10 +310,10 @@ $('#btn_transfer').click(function () { destination: dest.note.id, destination_alias: dest.name }).done(function () { - if (source.note.membership && source.note.membership.date_end < new Date().toISOString()) { + if (source.note.membership && source.note.membership.date_end <= new Date().toISOString()) { addMsg(interpolate(gettext('Warning, the emitter note %s is no more a BDE member.'), [source.name]), 'danger', 30000) } - if (dest.note.membership && dest.note.membership.date_end < new Date().toISOString()) { + if (dest.note.membership && dest.note.membership.date_end <= new Date().toISOString()) { addMsg(interpolate(gettext('Warning, the destination note %s is no more a BDE member.'), [dest.name]), 'danger', 30000) } @@ -414,7 +414,7 @@ $('#btn_transfer').click(function () { bank: $('#bank').val() }).done(function () { addMsg(gettext('Credit/debit succeed!'), 'success', 10000) - if (user_note.membership && user_note.membership.date_end < new Date().toISOString()) { addMsg(gettext('Warning, the emitter note %s is no more a BDE member.'), 'danger', 10000) } + if (user_note.membership && user_note.membership.date_end <= new Date().toISOString()) { addMsg(gettext('Warning, the emitter note %s is no more a BDE member.'), 'danger', 10000) } reset() }).fail(function (err) { const errObj = JSON.parse(err.responseText) diff --git a/apps/treasury/migrations/0011_sogecredit_valid.py b/apps/treasury/migrations/0011_sogecredit_valid.py new file mode 100644 index 00000000..44ef6c90 --- /dev/null +++ b/apps/treasury/migrations/0011_sogecredit_valid.py @@ -0,0 +1,18 @@ +# Generated by Django 5.2.6 on 2025-09-28 20:12 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('treasury', '0010_alter_invoice_bde'), + ] + + operations = [ + migrations.AddField( + model_name='sogecredit', + name='valid', + field=models.BooleanField(blank=True, default=False, verbose_name='Valid'), + ), + ] diff --git a/apps/treasury/models.py b/apps/treasury/models.py index 48709801..63e1d7cd 100644 --- a/apps/treasury/models.py +++ b/apps/treasury/models.py @@ -308,6 +308,12 @@ class SogeCredit(models.Model): null=True, ) + valid = models.BooleanField( + default=False, + verbose_name=_("Valid"), + blank=True, + ) + class Meta: verbose_name = _("Credit from the Société générale") verbose_name_plural = _("Credits from the Société générale") @@ -338,7 +344,7 @@ class SogeCredit(models.Model): credit_transaction.save() credit_transaction.refresh_from_db() self.credit_transaction = credit_transaction - elif not self.valid: + elif not self.valid_legacy: self.credit_transaction.amount = self.amount self.credit_transaction._force_save = True self.credit_transaction.save() @@ -346,12 +352,12 @@ class SogeCredit(models.Model): return super().save(*args, **kwargs) @property - def valid(self): + def valid_legacy(self): return self.credit_transaction and self.credit_transaction.valid @property def amount(self): - if self.valid: + if self.valid_legacy: return self.credit_transaction.total amount = 0 transactions_wei = self.transactions.filter(membership__club__weiclub__isnull=False) @@ -365,7 +371,7 @@ class SogeCredit(models.Model): The Sogé credit may be created after the user already paid its memberships. We query transactions and update the credit, if it is unvalid. """ - if self.valid or not self.pk: + if self.valid_legacy or not self.pk: return # Soge do not pay BDE and kfet memberships since 2022 @@ -405,7 +411,7 @@ class SogeCredit(models.Model): Invalidating a Société générale delete the transaction of the bank if it was already created. Treasurers must know what they do, With Great Power Comes Great Responsibility... """ - if self.valid: + if self.valid_legacy: self.credit_transaction.valid = False self.credit_transaction.save() for tr in self.transactions.all(): @@ -414,7 +420,7 @@ class SogeCredit(models.Model): tr.save() def validate(self, force=False): - if self.valid and not force: + if self.valid_legacy and not force: # The credit is already done return diff --git a/apps/treasury/tests/test_treasury.py b/apps/treasury/tests/test_treasury.py index 8feb5485..d1d5a414 100644 --- a/apps/treasury/tests/test_treasury.py +++ b/apps/treasury/tests/test_treasury.py @@ -359,7 +359,7 @@ class TestSogeCredits(TestCase): )) self.assertRedirects(response, reverse("treasury:manage_soge_credit", args=(soge_credit.pk,)), 302, 200) soge_credit.refresh_from_db() - self.assertTrue(soge_credit.valid) + self.assertTrue(soge_credit.valid_legacy) self.user.note.refresh_from_db() self.assertEqual( Transaction.objects.filter(Q(source=self.user.note) | Q(destination=self.user.note)).count(), 3) diff --git a/requirements.txt b/requirements.txt index 20c53dfa..464cd4ac 100644 --- a/requirements.txt +++ b/requirements.txt @@ -12,7 +12,7 @@ django-filter~=25.1 django-mailer~=2.3.2 django-oauth-toolkit~=3.0.1 django-phonenumber-field~=8.1.0 -django-polymorphic~=3.1.0 +django-polymorphic~=4.1.0 djangorestframework~=3.16.0 django-rest-polymorphic~=0.1.10 django-tables2~=2.7.5