From 2a5893aa7940ab130bce05c07442b70ff63e962f Mon Sep 17 00:00:00 2001 From: imperosol Date: Wed, 19 Nov 2025 19:54:45 +0100 Subject: [PATCH 1/6] remove `Selling.is_validated` --- core/tests/test_user.py | 8 +------- counter/management/commands/dump_accounts.py | 1 - .../0035_remove_selling_is_validated_and_more.py | 12 ++++++++++++ counter/models.py | 4 +--- counter/tests/test_account_dump.py | 1 - counter/views/invoice.py | 1 - eboutic/models.py | 1 - eboutic/tests/test_basket.py | 11 +++++++---- 8 files changed, 21 insertions(+), 18 deletions(-) create mode 100644 counter/migrations/0035_remove_selling_is_validated_and_more.py diff --git a/core/tests/test_user.py b/core/tests/test_user.py index 6d99d2a2..77ca0fe0 100644 --- a/core/tests/test_user.py +++ b/core/tests/test_user.py @@ -186,13 +186,7 @@ class TestFilterInactive(TestCase): time_active = now() - settings.SITH_ACCOUNT_INACTIVITY_DELTA + timedelta(days=1) time_inactive = time_active - timedelta(days=3) counter, seller = baker.make(Counter), baker.make(User) - sale_recipe = Recipe( - Selling, - counter=counter, - club=counter.club, - seller=seller, - is_validated=True, - ) + sale_recipe = Recipe(Selling, counter=counter, club=counter.club, seller=seller) cls.users = [ baker.make(User), diff --git a/counter/management/commands/dump_accounts.py b/counter/management/commands/dump_accounts.py index b25cb93c..de8d113a 100644 --- a/counter/management/commands/dump_accounts.py +++ b/counter/management/commands/dump_accounts.py @@ -119,7 +119,6 @@ class Command(BaseCommand): quantity=1, unit_price=account.amount, date=now(), - is_validated=True, ) for account in accounts ] diff --git a/counter/migrations/0035_remove_selling_is_validated_and_more.py b/counter/migrations/0035_remove_selling_is_validated_and_more.py new file mode 100644 index 00000000..37d4997b --- /dev/null +++ b/counter/migrations/0035_remove_selling_is_validated_and_more.py @@ -0,0 +1,12 @@ +# Generated by Django 5.2.8 on 2025-11-19 17:59 + +from django.db import migrations, models +from django.db.migrations.state import StateApps + + +class Migration(migrations.Migration): + dependencies = [("counter", "0034_alter_selling_date_selling_date_month_idx")] + + operations = [ + migrations.RemoveField(model_name="selling", name="is_validated"), + ] diff --git a/counter/models.py b/counter/models.py index f98f3e44..1e07be3b 100644 --- a/counter/models.py +++ b/counter/models.py @@ -856,7 +856,6 @@ class Selling(models.Model): choices=[("SITH_ACCOUNT", _("Sith account")), ("CARD", _("Credit card"))], default="SITH_ACCOUNT", ) - is_validated = models.BooleanField(_("is validated"), default=False) objects = SellingQuerySet.as_manager() @@ -875,10 +874,9 @@ class Selling(models.Model): if not self.date: self.date = timezone.now() self.full_clean() - if not self.is_validated: + if self._state.adding and self.payment_method == "SITH_ACCOUNT": self.customer.amount -= self.quantity * self.unit_price self.customer.save(allow_negative=allow_negative) - self.is_validated = True user = self.customer.user if user.was_subscribed: if ( diff --git a/counter/tests/test_account_dump.py b/counter/tests/test_account_dump.py index db074efb..0d41576e 100644 --- a/counter/tests/test_account_dump.py +++ b/counter/tests/test_account_dump.py @@ -116,7 +116,6 @@ class TestAccountDumpCommand(TestAccountDump): operation: Selling = customer.buyings.order_by("date").last() assert operation.unit_price == initial_amount assert operation.counter_id == settings.SITH_COUNTER_ACCOUNT_DUMP_ID - assert operation.is_validated is True dump = customer.dumps.last() assert dump.dump_operation == operation diff --git a/counter/views/invoice.py b/counter/views/invoice.py index 63585796..c42090d6 100644 --- a/counter/views/invoice.py +++ b/counter/views/invoice.py @@ -75,7 +75,6 @@ class InvoiceCallView( kwargs["sum_cb"] += ( Selling.objects.filter( payment_method="CARD", - is_validated=True, date__gte=start_date, date__lte=end_date, ) diff --git a/eboutic/models.py b/eboutic/models.py index f0016073..6d71e025 100644 --- a/eboutic/models.py +++ b/eboutic/models.py @@ -268,7 +268,6 @@ class Invoice(models.Model): unit_price=i.product_unit_price, quantity=i.quantity, payment_method="CARD", - is_validated=True, date=self.date, ) new.save() diff --git a/eboutic/tests/test_basket.py b/eboutic/tests/test_basket.py index ff7f2077..b4d0cedf 100644 --- a/eboutic/tests/test_basket.py +++ b/eboutic/tests/test_basket.py @@ -108,10 +108,13 @@ def test_eboutic_basket_expiry( client.force_login(customer.user) - for date in sellings: - sale_recipe.make( - customer=customer, counter=eboutic, date=date, is_validated=True - ) + sale_recipe.make( + customer=customer, + counter=eboutic, + date=iter(sellings), + _quantity=len(sellings), + _bulk_create=True, + ) for date in refillings: refill_recipe.make(customer=customer, counter=eboutic, date=date) From 78fe4e52cabea35f5a2b24b50acd6b43d01ac80a Mon Sep 17 00:00:00 2001 From: imperosol Date: Wed, 19 Nov 2025 19:56:21 +0100 Subject: [PATCH 2/6] make `Selling.payment_method` a SmallIntegerField --- ...35_remove_selling_is_validated_and_more.py | 26 +++++++++++++++++++ counter/models.py | 25 +++++++++++------- counter/tests/test_customer.py | 5 +--- counter/views/invoice.py | 2 +- eboutic/models.py | 6 +++-- eboutic/tests/test_payment.py | 8 +++--- eboutic/views.py | 2 +- rootplace/tests/test_merge_users.py | 4 --- 8 files changed, 53 insertions(+), 25 deletions(-) diff --git a/counter/migrations/0035_remove_selling_is_validated_and_more.py b/counter/migrations/0035_remove_selling_is_validated_and_more.py index 37d4997b..b5ecf0b6 100644 --- a/counter/migrations/0035_remove_selling_is_validated_and_more.py +++ b/counter/migrations/0035_remove_selling_is_validated_and_more.py @@ -4,9 +4,35 @@ from django.db import migrations, models from django.db.migrations.state import StateApps +def migrate_payment_method(apps: StateApps, schema_editor): + Selling = apps.get_model("counter", "Selling") + Selling.objects.filter(payment_method_str="CARD").update(payment_method=1) + + +def migrate_payment_method_reverse(apps: StateApps, schema_editor): + Selling = apps.get_model("counter", "Selling") + Selling.objects.filter(payment_method=1).update(payment_method_str="CARD") + + class Migration(migrations.Migration): dependencies = [("counter", "0034_alter_selling_date_selling_date_month_idx")] operations = [ migrations.RemoveField(model_name="selling", name="is_validated"), + migrations.RenameField( + model_name="selling", + old_name="payment_method", + new_name="payment_method_str", + ), + migrations.AddField( + model_name="selling", + name="payment_method", + field=models.PositiveSmallIntegerField( + choices=[(0, "Sith account"), (1, "Credit card")], + default=0, + verbose_name="payment method", + ), + ), + migrations.RunPython(migrate_payment_method, migrate_payment_method_reverse), + migrations.RemoveField(model_name="selling", name="payment_method_str"), ] diff --git a/counter/models.py b/counter/models.py index 1e07be3b..7324e0c2 100644 --- a/counter/models.py +++ b/counter/models.py @@ -80,7 +80,8 @@ class CustomerQuerySet(models.QuerySet): ) money_out = Subquery( Selling.objects.filter( - customer=OuterRef("pk"), payment_method="SITH_ACCOUNT" + customer=OuterRef("pk"), + payment_method=Selling.PaymentMethod.SITH_ACCOUNT, ) .values("customer_id") .annotate(res=Sum(F("unit_price") * F("quantity"), default=0)) @@ -814,6 +815,10 @@ class SellingQuerySet(models.QuerySet): class Selling(models.Model): """Handle the sellings.""" + class PaymentMethod(models.IntegerChoices): + SITH_ACCOUNT = 0, _("Sith account") + CARD = 1, _("Credit card") + # We make sure that sellings have a way begger label than any product name is allowed to label = models.CharField(_("label"), max_length=128) product = models.ForeignKey( @@ -850,11 +855,8 @@ class Selling(models.Model): on_delete=models.SET_NULL, ) date = models.DateTimeField(_("date"), db_index=True) - payment_method = models.CharField( - _("payment method"), - max_length=255, - choices=[("SITH_ACCOUNT", _("Sith account")), ("CARD", _("Credit card"))], - default="SITH_ACCOUNT", + payment_method = models.PositiveSmallIntegerField( + _("payment method"), choices=PaymentMethod, default=PaymentMethod.SITH_ACCOUNT ) objects = SellingQuerySet.as_manager() @@ -874,7 +876,10 @@ class Selling(models.Model): if not self.date: self.date = timezone.now() self.full_clean() - if self._state.adding and self.payment_method == "SITH_ACCOUNT": + if ( + self._state.adding + and self.payment_method == self.PaymentMethod.SITH_ACCOUNT + ): self.customer.amount -= self.quantity * self.unit_price self.customer.save(allow_negative=allow_negative) user = self.customer.user @@ -946,7 +951,9 @@ class Selling(models.Model): def is_owned_by(self, user: User) -> bool: if user.is_anonymous: return False - return self.payment_method != "CARD" and user.is_owner(self.counter) + return self.payment_method != self.PaymentMethod.CARD and user.is_owner( + self.counter + ) def can_be_viewed_by(self, user: User) -> bool: if ( @@ -956,7 +963,7 @@ class Selling(models.Model): return user == self.customer.user def delete(self, *args, **kwargs): - if self.payment_method == "SITH_ACCOUNT": + if self.payment_method == Selling.PaymentMethod.SITH_ACCOUNT: self.customer.amount += self.quantity * self.unit_price self.customer.save() super().delete(*args, **kwargs) diff --git a/counter/tests/test_customer.py b/counter/tests/test_customer.py index 3676a701..311e48ed 100644 --- a/counter/tests/test_customer.py +++ b/counter/tests/test_customer.py @@ -298,7 +298,6 @@ def test_update_balance(): _quantity=len(customers), unit_price=10, quantity=1, - payment_method="SITH_ACCOUNT", _save_related=True, ), *sale_recipe.prepare( @@ -306,14 +305,12 @@ def test_update_balance(): _quantity=3, unit_price=5, quantity=2, - payment_method="SITH_ACCOUNT", _save_related=True, ), sale_recipe.prepare( customer=customers[4], quantity=1, unit_price=50, - payment_method="SITH_ACCOUNT", _save_related=True, ), *sale_recipe.prepare( @@ -324,7 +321,7 @@ def test_update_balance(): _quantity=len(customers), unit_price=50, quantity=1, - payment_method="CARD", + payment_method=Selling.PaymentMethod.CARD, _save_related=True, ), ] diff --git a/counter/views/invoice.py b/counter/views/invoice.py index c42090d6..11702803 100644 --- a/counter/views/invoice.py +++ b/counter/views/invoice.py @@ -74,7 +74,7 @@ class InvoiceCallView( ).aggregate(res=Sum("amount", default=0))["res"] kwargs["sum_cb"] += ( Selling.objects.filter( - payment_method="CARD", + payment_method=Selling.PaymentMethod.CARD, date__gte=start_date, date__lte=end_date, ) diff --git a/eboutic/models.py b/eboutic/models.py index 6d71e025..a2054610 100644 --- a/eboutic/models.py +++ b/eboutic/models.py @@ -110,7 +110,9 @@ class Basket(models.Model): )["total"] ) - def generate_sales(self, counter, seller: User, payment_method: str): + def generate_sales( + self, counter, seller: User, payment_method: Selling.PaymentMethod + ): """Generate a list of sold items corresponding to the items of this basket WITHOUT saving them NOR deleting the basket. @@ -267,7 +269,7 @@ class Invoice(models.Model): customer=customer, unit_price=i.product_unit_price, quantity=i.quantity, - payment_method="CARD", + payment_method=Selling.PaymentMethod.CARD, date=self.date, ) new.save() diff --git a/eboutic/tests/test_payment.py b/eboutic/tests/test_payment.py index dd619169..813e82c8 100644 --- a/eboutic/tests/test_payment.py +++ b/eboutic/tests/test_payment.py @@ -114,13 +114,13 @@ class TestPaymentSith(TestPaymentBase): "quantity" ) assert len(sellings) == 2 - assert sellings[0].payment_method == "SITH_ACCOUNT" + assert sellings[0].payment_method == Selling.PaymentMethod.SITH_ACCOUNT assert sellings[0].quantity == 1 assert sellings[0].unit_price == self.snack.selling_price assert sellings[0].counter.type == "EBOUTIC" assert sellings[0].product == self.snack - assert sellings[1].payment_method == "SITH_ACCOUNT" + assert sellings[1].payment_method == Selling.PaymentMethod.SITH_ACCOUNT assert sellings[1].quantity == 2 assert sellings[1].unit_price == self.beer.selling_price assert sellings[1].counter.type == "EBOUTIC" @@ -198,13 +198,13 @@ class TestPaymentCard(TestPaymentBase): "quantity" ) assert len(sellings) == 2 - assert sellings[0].payment_method == "CARD" + assert sellings[0].payment_method == Selling.PaymentMethod.CARD assert sellings[0].quantity == 1 assert sellings[0].unit_price == self.snack.selling_price assert sellings[0].counter.type == "EBOUTIC" assert sellings[0].product == self.snack - assert sellings[1].payment_method == "CARD" + assert sellings[1].payment_method == Selling.PaymentMethod.CARD assert sellings[1].quantity == 2 assert sellings[1].unit_price == self.beer.selling_price assert sellings[1].counter.type == "EBOUTIC" diff --git a/eboutic/views.py b/eboutic/views.py index fa25df66..74cdc7ad 100644 --- a/eboutic/views.py +++ b/eboutic/views.py @@ -275,7 +275,7 @@ class EbouticPayWithSith(CanViewMixin, SingleObjectMixin, View): return redirect("eboutic:payment_result", "failure") eboutic = get_eboutic() - sales = basket.generate_sales(eboutic, basket.user, "SITH_ACCOUNT") + sales = basket.generate_sales(eboutic, basket.user, Selling.PaymentMethod.SITH_ACCOUNT) try: with transaction.atomic(): # Selling.save has some important business logic in it. diff --git a/rootplace/tests/test_merge_users.py b/rootplace/tests/test_merge_users.py index 294e2bae..63c406cd 100644 --- a/rootplace/tests/test_merge_users.py +++ b/rootplace/tests/test_merge_users.py @@ -114,7 +114,6 @@ class TestMergeUser(TestCase): seller=self.root, unit_price=2, quantity=2, - payment_method="SITH_ACCOUNT", ).save() Selling( label="barbar", @@ -125,7 +124,6 @@ class TestMergeUser(TestCase): seller=self.root, unit_price=2, quantity=4, - payment_method="SITH_ACCOUNT", ).save() today = localtime(now()).date() # both subscriptions began last month and shall end in 5 months @@ -197,7 +195,6 @@ class TestMergeUser(TestCase): seller=self.root, unit_price=2, quantity=4, - payment_method="SITH_ACCOUNT", ).save() data = {"user1": self.to_keep.id, "user2": self.to_delete.id} res = self.client.post(reverse("rootplace:merge"), data) @@ -225,7 +222,6 @@ class TestMergeUser(TestCase): seller=self.root, unit_price=2, quantity=4, - payment_method="SITH_ACCOUNT", ).save() data = {"user1": self.to_keep.id, "user2": self.to_delete.id} res = self.client.post(reverse("rootplace:merge"), data) From 56c2c2b70e7fdddbe92df187532f8bb93148d3b6 Mon Sep 17 00:00:00 2001 From: imperosol Date: Wed, 19 Nov 2025 20:05:35 +0100 Subject: [PATCH 3/6] remove `Refilling.is_validated` --- core/management/commands/populate_more.py | 1 - ...35_remove_selling_is_validated_and_more.py | 1 + counter/models.py | 4 +-- counter/tests/test_counter.py | 2 +- counter/views/invoice.py | 5 +--- eboutic/tests/test_basket.py | 25 ++++++++++++------- 6 files changed, 20 insertions(+), 18 deletions(-) diff --git a/core/management/commands/populate_more.py b/core/management/commands/populate_more.py index 38803dc8..76115c70 100644 --- a/core/management/commands/populate_more.py +++ b/core/management/commands/populate_more.py @@ -350,7 +350,6 @@ class Command(BaseCommand): date=make_aware( self.faker.date_time_between(customer.since, localdate()) ), - is_validated=True, ) ) sales.extend(this_customer_sales) diff --git a/counter/migrations/0035_remove_selling_is_validated_and_more.py b/counter/migrations/0035_remove_selling_is_validated_and_more.py index b5ecf0b6..83da9643 100644 --- a/counter/migrations/0035_remove_selling_is_validated_and_more.py +++ b/counter/migrations/0035_remove_selling_is_validated_and_more.py @@ -19,6 +19,7 @@ class Migration(migrations.Migration): operations = [ migrations.RemoveField(model_name="selling", name="is_validated"), + migrations.RemoveField(model_name="refilling", name="is_validated"), migrations.RenameField( model_name="selling", old_name="payment_method", diff --git a/counter/models.py b/counter/models.py index 7324e0c2..f056102b 100644 --- a/counter/models.py +++ b/counter/models.py @@ -755,7 +755,6 @@ class Refilling(models.Model): bank = models.CharField( _("bank"), max_length=255, choices=settings.SITH_COUNTER_BANK, default="OTHER" ) - is_validated = models.BooleanField(_("is validated"), default=False) objects = RefillingQuerySet.as_manager() @@ -772,10 +771,9 @@ class Refilling(models.Model): if not self.date: self.date = timezone.now() self.full_clean() - if not self.is_validated: + if self._state.adding: self.customer.amount += self.amount self.customer.save() - self.is_validated = True if self.customer.user.preferences.notify_on_refill: Notification( user=self.customer.user, diff --git a/counter/tests/test_counter.py b/counter/tests/test_counter.py index af0e07ad..45b7bb13 100644 --- a/counter/tests/test_counter.py +++ b/counter/tests/test_counter.py @@ -53,7 +53,7 @@ def set_age(user: User, age: int): def force_refill_user(user: User, amount: Decimal | int): - baker.make(Refilling, amount=amount, customer=user.customer, is_validated=False) + baker.make(Refilling, amount=amount, customer=user.customer) class TestFullClickBase(TestCase): diff --git a/counter/views/invoice.py b/counter/views/invoice.py index 11702803..d990b609 100644 --- a/counter/views/invoice.py +++ b/counter/views/invoice.py @@ -67,10 +67,7 @@ class InvoiceCallView( end_date = start_date + relativedelta(months=1) kwargs["sum_cb"] = Refilling.objects.filter( - payment_method="CARD", - is_validated=True, - date__gte=start_date, - date__lte=end_date, + payment_method="CARD", date__gte=start_date, date__lte=end_date ).aggregate(res=Sum("amount", default=0))["res"] kwargs["sum_cb"] += ( Selling.objects.filter( diff --git a/eboutic/tests/test_basket.py b/eboutic/tests/test_basket.py index b4d0cedf..539502cc 100644 --- a/eboutic/tests/test_basket.py +++ b/eboutic/tests/test_basket.py @@ -108,15 +108,22 @@ def test_eboutic_basket_expiry( client.force_login(customer.user) - sale_recipe.make( - customer=customer, - counter=eboutic, - date=iter(sellings), - _quantity=len(sellings), - _bulk_create=True, - ) - for date in refillings: - refill_recipe.make(customer=customer, counter=eboutic, date=date) + if sellings: + sale_recipe.make( + customer=customer, + counter=eboutic, + date=iter(sellings), + _quantity=len(sellings), + _bulk_create=True, + ) + if refillings: + refill_recipe.make( + customer=customer, + counter=eboutic, + date=iter(refillings), + _quantity=len(refillings), + _bulk_create=True, + ) assert ( f'x-data="basket({int(expected.timestamp() * 1000) if expected else "null"})"' From ad87617018e77736c9b9102af97cf6a77e11084a Mon Sep 17 00:00:00 2001 From: imperosol Date: Wed, 19 Nov 2025 20:18:49 +0100 Subject: [PATCH 4/6] remove `Refilling.bank` --- core/tests/test_user.py | 4 +++- counter/forms.py | 5 +---- .../0035_remove_selling_is_validated_and_more.py | 1 + counter/models.py | 8 +------- counter/tests/test_counter.py | 12 ++---------- eboutic/models.py | 1 - sith/settings.py | 13 ------------- 7 files changed, 8 insertions(+), 36 deletions(-) diff --git a/core/tests/test_user.py b/core/tests/test_user.py index 77ca0fe0..b90e626e 100644 --- a/core/tests/test_user.py +++ b/core/tests/test_user.py @@ -186,7 +186,9 @@ class TestFilterInactive(TestCase): time_active = now() - settings.SITH_ACCOUNT_INACTIVITY_DELTA + timedelta(days=1) time_inactive = time_active - timedelta(days=3) counter, seller = baker.make(Counter), baker.make(User) - sale_recipe = Recipe(Selling, counter=counter, club=counter.club, seller=seller) + sale_recipe = Recipe( + Selling, counter=counter, club=counter.club, seller=seller, unit_price=0 + ) cls.users = [ baker.make(User), diff --git a/counter/forms.py b/counter/forms.py index 5e144d44..1b59855a 100644 --- a/counter/forms.py +++ b/counter/forms.py @@ -146,7 +146,7 @@ class RefillForm(forms.ModelForm): class Meta: model = Refilling - fields = ["amount", "payment_method", "bank"] + fields = ["amount", "payment_method"] widgets = {"payment_method": forms.RadioSelect} def __init__(self, *args, **kwargs): @@ -160,9 +160,6 @@ class RefillForm(forms.ModelForm): if self.fields["payment_method"].initial not in self.allowed_refilling_methods: self.fields["payment_method"].initial = self.allowed_refilling_methods[0] - if "CHECK" not in self.allowed_refilling_methods: - del self.fields["bank"] - class CounterEditForm(forms.ModelForm): class Meta: diff --git a/counter/migrations/0035_remove_selling_is_validated_and_more.py b/counter/migrations/0035_remove_selling_is_validated_and_more.py index 83da9643..94513a43 100644 --- a/counter/migrations/0035_remove_selling_is_validated_and_more.py +++ b/counter/migrations/0035_remove_selling_is_validated_and_more.py @@ -20,6 +20,7 @@ class Migration(migrations.Migration): operations = [ migrations.RemoveField(model_name="selling", name="is_validated"), migrations.RemoveField(model_name="refilling", name="is_validated"), + migrations.RemoveField(model_name="refilling", name="bank"), migrations.RenameField( model_name="selling", old_name="payment_method", diff --git a/counter/models.py b/counter/models.py index f056102b..4f0bee12 100644 --- a/counter/models.py +++ b/counter/models.py @@ -747,13 +747,7 @@ class Refilling(models.Model): ) date = models.DateTimeField(_("date")) payment_method = models.CharField( - _("payment method"), - max_length=255, - choices=PAYMENT_METHOD, - default="CARD", - ) - bank = models.CharField( - _("bank"), max_length=255, choices=settings.SITH_COUNTER_BANK, default="OTHER" + _("payment method"), max_length=255, choices=PAYMENT_METHOD, default="CARD" ) objects = RefillingQuerySet.as_manager() diff --git a/counter/tests/test_counter.py b/counter/tests/test_counter.py index 45b7bb13..e30a2b43 100644 --- a/counter/tests/test_counter.py +++ b/counter/tests/test_counter.py @@ -119,11 +119,7 @@ class TestRefilling(TestFullClickBase): "counter:refilling_create", kwargs={"customer_id": user.pk}, ), - { - "amount": str(amount), - "payment_method": "CASH", - "bank": "OTHER", - }, + {"amount": str(amount), "payment_method": "CASH"}, HTTP_REFERER=reverse( "counter:click", kwargs={"counter_id": counter.id, "user_id": user.pk}, @@ -149,11 +145,7 @@ class TestRefilling(TestFullClickBase): "counter:refilling_create", kwargs={"customer_id": self.customer.pk}, ), - { - "amount": "10", - "payment_method": "CASH", - "bank": "OTHER", - }, + {"amount": "10", "payment_method": "CASH"}, ) self.client.force_login(self.club_admin) diff --git a/eboutic/models.py b/eboutic/models.py index a2054610..2a4e14b5 100644 --- a/eboutic/models.py +++ b/eboutic/models.py @@ -254,7 +254,6 @@ class Invoice(models.Model): operator=self.user, amount=i.product_unit_price * i.quantity, payment_method="CARD", - bank="OTHER", date=self.date, ) new.save() diff --git a/sith/settings.py b/sith/settings.py index 8647d8e9..7c6aab4e 100644 --- a/sith/settings.py +++ b/sith/settings.py @@ -440,19 +440,6 @@ SITH_SUBSCRIPTION_LOCATIONS = [ SITH_COUNTER_BARS = [(1, "MDE"), (2, "Foyer"), (35, "La Gommette")] -SITH_COUNTER_BANK = [ - ("OTHER", "Autre"), - ("SOCIETE-GENERALE", "Société générale"), - ("BANQUE-POPULAIRE", "Banque populaire"), - ("BNP", "BNP"), - ("CAISSE-EPARGNE", "Caisse d'épargne"), - ("CIC", "CIC"), - ("CREDIT-AGRICOLE", "Crédit Agricole"), - ("CREDIT-MUTUEL", "Credit Mutuel"), - ("CREDIT-LYONNAIS", "Credit Lyonnais"), - ("LA-POSTE", "La Poste"), -] - SITH_PEDAGOGY_UV_TYPE = [ ("FREE", _("Free")), ("CS", _("CS")), From c588e5117d2a565be9976ca9f7e2907680ea1f53 Mon Sep 17 00:00:00 2001 From: imperosol Date: Wed, 19 Nov 2025 20:49:06 +0100 Subject: [PATCH 5/6] make `Refilling.payment_method` a SmallIntegerField --- counter/apps.py | 6 --- counter/forms.py | 5 +- ...35_remove_selling_is_validated_and_more.py | 50 +++++++++++++++++-- counter/models.py | 10 ++-- counter/tests/test_counter.py | 10 ++-- counter/views/invoice.py | 4 +- eboutic/models.py | 2 +- eboutic/views.py | 4 +- subscription/views.py | 3 +- 9 files changed, 69 insertions(+), 25 deletions(-) diff --git a/counter/apps.py b/counter/apps.py index 9348cd1c..54e7ad4c 100644 --- a/counter/apps.py +++ b/counter/apps.py @@ -24,12 +24,6 @@ from django.apps import AppConfig from django.utils.translation import gettext_lazy as _ -PAYMENT_METHOD = [ - ("CHECK", _("Check")), - ("CASH", _("Cash")), - ("CARD", _("Credit card")), -] - class CounterConfig(AppConfig): name = "counter" diff --git a/counter/forms.py b/counter/forms.py index 1b59855a..e2bf016e 100644 --- a/counter/forms.py +++ b/counter/forms.py @@ -136,7 +136,10 @@ class GetUserForm(forms.Form): class RefillForm(forms.ModelForm): - allowed_refilling_methods = ["CASH", "CARD"] + allowed_refilling_methods = [ + Refilling.PaymentMethod.CASH, + Refilling.PaymentMethod.CARD, + ] error_css_class = "error" required_css_class = "required" diff --git a/counter/migrations/0035_remove_selling_is_validated_and_more.py b/counter/migrations/0035_remove_selling_is_validated_and_more.py index 94513a43..a8a2e115 100644 --- a/counter/migrations/0035_remove_selling_is_validated_and_more.py +++ b/counter/migrations/0035_remove_selling_is_validated_and_more.py @@ -2,18 +2,42 @@ from django.db import migrations, models from django.db.migrations.state import StateApps +from django.db.models import Case, When -def migrate_payment_method(apps: StateApps, schema_editor): +def migrate_selling_payment_method(apps: StateApps, schema_editor): + # 0 <=> SITH_ACCOUNT is the default value, so no need to migrate it Selling = apps.get_model("counter", "Selling") Selling.objects.filter(payment_method_str="CARD").update(payment_method=1) -def migrate_payment_method_reverse(apps: StateApps, schema_editor): +def migrate_selling_payment_method_reverse(apps: StateApps, schema_editor): Selling = apps.get_model("counter", "Selling") Selling.objects.filter(payment_method=1).update(payment_method_str="CARD") +def migrate_refilling_payment_method(apps: StateApps, schema_editor): + Refilling = apps.get_model("counter", "Refilling") + Refilling.objects.update( + payment_method=Case( + When(payment_method_str="CARD", then=0), + When(payment_method_str="CASH", then=1), + When(payment_method_str="CHECK", then=2), + ) + ) + + +def migrate_refilling_payment_method_reverse(apps: StateApps, schema_editor): + Refilling = apps.get_model("counter", "Refilling") + Refilling.objects.update( + payment_method_str=Case( + When(payment_method=0, then="CARD"), + When(payment_method=1, then="CASH"), + When(payment_method=2, then="CHECK"), + ) + ) + + class Migration(migrations.Migration): dependencies = [("counter", "0034_alter_selling_date_selling_date_month_idx")] @@ -35,6 +59,26 @@ class Migration(migrations.Migration): verbose_name="payment method", ), ), - migrations.RunPython(migrate_payment_method, migrate_payment_method_reverse), + migrations.RunPython( + migrate_selling_payment_method, migrate_selling_payment_method_reverse + ), migrations.RemoveField(model_name="selling", name="payment_method_str"), + migrations.RenameField( + model_name="refilling", + old_name="payment_method", + new_name="payment_method_str", + ), + migrations.AddField( + model_name="refilling", + name="payment_method", + field=models.PositiveSmallIntegerField( + choices=[(0, "Credit card"), (1, "Cash"), (2, "Check")], + default=0, + verbose_name="payment method", + ), + ), + migrations.RunPython( + migrate_refilling_payment_method, migrate_refilling_payment_method_reverse + ), + migrations.RemoveField(model_name="refilling", name="payment_method_str"), ] diff --git a/counter/models.py b/counter/models.py index 4f0bee12..996f22e6 100644 --- a/counter/models.py +++ b/counter/models.py @@ -44,7 +44,6 @@ from club.models import Club from core.fields import ResizedImageField from core.models import Group, Notification, User from core.utils import get_start_of_semester -from counter.apps import PAYMENT_METHOD from counter.fields import CurrencyField from subscription.models import Subscription @@ -732,6 +731,11 @@ class RefillingQuerySet(models.QuerySet): class Refilling(models.Model): """Handle the refilling.""" + class PaymentMethod(models.IntegerChoices): + CARD = 0, _("Credit card") + CASH = 1, _("Cash") + CHECK = 2, _("Check") + counter = models.ForeignKey( Counter, related_name="refillings", blank=False, on_delete=models.CASCADE ) @@ -746,8 +750,8 @@ class Refilling(models.Model): Customer, related_name="refillings", blank=False, on_delete=models.CASCADE ) date = models.DateTimeField(_("date")) - payment_method = models.CharField( - _("payment method"), max_length=255, choices=PAYMENT_METHOD, default="CARD" + payment_method = models.PositiveSmallIntegerField( + _("payment method"), choices=PaymentMethod, default=PaymentMethod.CARD ) objects = RefillingQuerySet.as_manager() diff --git a/counter/tests/test_counter.py b/counter/tests/test_counter.py index e30a2b43..4f3e2df6 100644 --- a/counter/tests/test_counter.py +++ b/counter/tests/test_counter.py @@ -115,14 +115,10 @@ class TestRefilling(TestFullClickBase): ) -> HttpResponse: used_client = client if client is not None else self.client return used_client.post( - reverse( - "counter:refilling_create", - kwargs={"customer_id": user.pk}, - ), - {"amount": str(amount), "payment_method": "CASH"}, + reverse("counter:refilling_create", kwargs={"customer_id": user.pk}), + {"amount": str(amount), "payment_method": Refilling.PaymentMethod.CASH}, HTTP_REFERER=reverse( - "counter:click", - kwargs={"counter_id": counter.id, "user_id": user.pk}, + "counter:click", kwargs={"counter_id": counter.id, "user_id": user.pk} ), ) diff --git a/counter/views/invoice.py b/counter/views/invoice.py index d990b609..f6512f6c 100644 --- a/counter/views/invoice.py +++ b/counter/views/invoice.py @@ -67,7 +67,9 @@ class InvoiceCallView( end_date = start_date + relativedelta(months=1) kwargs["sum_cb"] = Refilling.objects.filter( - payment_method="CARD", date__gte=start_date, date__lte=end_date + payment_method=Refilling.PaymentMethod.CARD, + date__gte=start_date, + date__lte=end_date, ).aggregate(res=Sum("amount", default=0))["res"] kwargs["sum_cb"] += ( Selling.objects.filter( diff --git a/eboutic/models.py b/eboutic/models.py index 2a4e14b5..5a37f70f 100644 --- a/eboutic/models.py +++ b/eboutic/models.py @@ -253,7 +253,7 @@ class Invoice(models.Model): customer=customer, operator=self.user, amount=i.product_unit_price * i.quantity, - payment_method="CARD", + payment_method=Refilling.PaymentMethod.CARD, date=self.date, ) new.save() diff --git a/eboutic/views.py b/eboutic/views.py index 74cdc7ad..f48c86c1 100644 --- a/eboutic/views.py +++ b/eboutic/views.py @@ -275,7 +275,9 @@ class EbouticPayWithSith(CanViewMixin, SingleObjectMixin, View): return redirect("eboutic:payment_result", "failure") eboutic = get_eboutic() - sales = basket.generate_sales(eboutic, basket.user, Selling.PaymentMethod.SITH_ACCOUNT) + sales = basket.generate_sales( + eboutic, basket.user, Selling.PaymentMethod.SITH_ACCOUNT + ) try: with transaction.atomic(): # Selling.save has some important business logic in it. diff --git a/subscription/views.py b/subscription/views.py index 035f9035..fb4cde07 100644 --- a/subscription/views.py +++ b/subscription/views.py @@ -24,7 +24,6 @@ from django.views.generic import CreateView, DetailView, TemplateView from django.views.generic.edit import FormView from core.views.group import PermissionGroupsUpdateView -from counter.apps import PAYMENT_METHOD from subscription.forms import ( SelectionDateForm, SubscriptionExistingUserForm, @@ -129,6 +128,6 @@ class SubscriptionsStatsView(FormView): subscription_end__gte=self.end_date, subscription_start__lte=self.start_date ) kwargs["subscriptions_types"] = settings.SITH_SUBSCRIPTIONS - kwargs["payment_types"] = PAYMENT_METHOD + kwargs["payment_types"] = settings.SITH_SUBSCRIPTION_PAYMENT_METHOD kwargs["locations"] = settings.SITH_SUBSCRIPTION_LOCATIONS return kwargs From 0c046b6164b21181cca5e187ca65c20c1521162f Mon Sep 17 00:00:00 2001 From: imperosol Date: Wed, 19 Nov 2025 21:02:01 +0100 Subject: [PATCH 6/6] translations --- locale/fr/LC_MESSAGES/django.po | 46 +++++++++++++++------------------ 1 file changed, 21 insertions(+), 25 deletions(-) diff --git a/locale/fr/LC_MESSAGES/django.po b/locale/fr/LC_MESSAGES/django.po index 4cfa038e..6be36d8f 100644 --- a/locale/fr/LC_MESSAGES/django.po +++ b/locale/fr/LC_MESSAGES/django.po @@ -6,7 +6,7 @@ msgid "" msgstr "" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2025-11-12 21:44+0100\n" +"POT-Creation-Date: 2025-11-19 21:00+0100\n" "PO-Revision-Date: 2016-07-18\n" "Last-Translator: Maréchal \n" @@ -2928,18 +2928,6 @@ msgstr "Photos" msgid "Account" msgstr "Compte" -#: counter/apps.py sith/settings.py -msgid "Check" -msgstr "Chèque" - -#: counter/apps.py sith/settings.py -msgid "Cash" -msgstr "Espèces" - -#: counter/apps.py counter/models.py sith/settings.py -msgid "Credit card" -msgstr "Carte bancaire" - #: counter/apps.py counter/models.py msgid "counter" msgstr "comptoir" @@ -3152,22 +3140,30 @@ msgstr "vendeurs" msgid "token" msgstr "jeton" +#: counter/models.py sith/settings.py +msgid "Credit card" +msgstr "Carte bancaire" + +#: counter/models.py sith/settings.py +msgid "Cash" +msgstr "Espèces" + +#: counter/models.py sith/settings.py +msgid "Check" +msgstr "Chèque" + #: counter/models.py subscription/models.py msgid "payment method" msgstr "méthode de paiement" -#: counter/models.py -msgid "bank" -msgstr "banque" - -#: counter/models.py -msgid "is validated" -msgstr "est validé" - #: counter/models.py msgid "refilling" msgstr "rechargement" +#: counter/models.py +msgid "Sith account" +msgstr "Compte utilisateur" + #: counter/models.py eboutic/models.py msgid "unit price" msgstr "prix unitaire" @@ -3176,10 +3172,6 @@ msgstr "prix unitaire" msgid "quantity" msgstr "quantité" -#: counter/models.py -msgid "Sith account" -msgstr "Compte utilisateur" - #: counter/models.py msgid "selling" msgstr "vente" @@ -3332,6 +3324,10 @@ msgid "" "“%(value)s” value has the correct format (YYYY-MM) but it is an invalid date." msgstr "La valeur « %(value)s » a le bon format, mais est une date invalide." +#: counter/models.py +msgid "is validated" +msgstr "est validé" + #: counter/models.py msgid "invoice date" msgstr "date de la facture"