unify eboutic and regular counter price selection

This commit is contained in:
imperosol
2026-03-08 16:29:48 +01:00
parent e188acc78b
commit 59d7fadf4f
6 changed files with 73 additions and 59 deletions

View File

@@ -119,4 +119,31 @@ class Migration(migrations.Migration):
migrations.RunPython(migrate_prices, reverse_code=migrations.RunPython.noop),
migrations.RemoveField(model_name="product", name="selling_price"),
migrations.RemoveField(model_name="product", name="special_selling_price"),
migrations.AlterField(
model_name="product",
name="description",
field=models.TextField(blank=True, default="", verbose_name="description"),
),
migrations.AlterField(
model_name="product",
name="product_type",
field=models.ForeignKey(
null=True,
on_delete=django.db.models.deletion.SET_NULL,
related_name="products",
to="counter.producttype",
verbose_name="product type",
),
),
migrations.AlterField(
model_name="productformula",
name="result",
field=models.OneToOneField(
help_text="The product got with the formula.",
on_delete=django.db.models.deletion.CASCADE,
related_name="formula",
to="counter.product",
verbose_name="result product",
),
),
]

View File

@@ -22,7 +22,7 @@ import string
from datetime import date, datetime, timedelta
from datetime import timezone as tz
from decimal import Decimal
from typing import Literal, Self
from typing import TYPE_CHECKING, Literal, Self
from dict2xml import dict2xml
from django.conf import settings
@@ -47,6 +47,9 @@ from core.utils import get_start_of_semester
from counter.fields import CurrencyField
from subscription.models import Subscription
if TYPE_CHECKING:
from collections.abc import Sequence
def get_eboutic() -> Counter:
return Counter.objects.filter(type="EBOUTIC").order_by("id").first()
@@ -356,13 +359,13 @@ class Product(models.Model):
QUANTITY_FOR_TRAY_PRICE = 6
name = models.CharField(_("name"), max_length=64)
description = models.TextField(_("description"), default="")
description = models.TextField(_("description"), blank=True, default="")
product_type = models.ForeignKey(
ProductType,
related_name="products",
verbose_name=_("product type"),
null=True,
blank=True,
blank=False,
on_delete=models.SET_NULL,
)
code = models.CharField(_("code"), max_length=16, blank=True)
@@ -726,13 +729,20 @@ class Counter(models.Model):
# but they share the same primary key
return self.type == "BAR" and any(b.pk == customer.pk for b in self.barmen_list)
def get_prices_for(self, customer: Customer) -> list[Price]:
return list(
Price.objects.filter(product__counters=self)
def get_prices_for(
self, customer: Customer, *, order_by: Sequence[str] | None = None
) -> list[Price]:
qs = (
Price.objects.filter(
product__counters=self, product__product_type__isnull=False
)
.for_user(customer.user)
.select_related("product", "product__product_type")
.prefetch_related("groups")
)
if order_by:
qs = qs.order_by(*order_by)
return list(qs)
class RefillingQuerySet(models.QuerySet):

View File

@@ -16,7 +16,7 @@ from counter.forms import (
ScheduledProductActionForm,
ScheduledProductActionFormSet,
)
from counter.models import Product, ScheduledProductAction
from counter.models import Product, ProductType, ScheduledProductAction
@pytest.mark.django_db
@@ -47,8 +47,7 @@ def test_create_actions_alongside_product():
form = ProductForm(
data={
"name": "foo",
"description": "bar",
"product_type": product.product_type_id,
"product_type": ProductType.objects.first(),
"club": product.club_id,
"code": "FOO",
"purchase_price": 1.0,
@@ -63,6 +62,7 @@ def test_create_actions_alongside_product():
"action-0-trigger_at": trigger_at,
},
)
form.is_valid()
assert form.is_valid()
product = form.save()
action = ScheduledProductAction.objects.last()

View File

@@ -39,6 +39,7 @@ from counter.models import (
Counter,
Customer,
Permanency,
ProductType,
Refilling,
ReturnableProduct,
Selling,
@@ -238,31 +239,38 @@ class TestCounterClick(TestFullClickBase):
old_subscriber_group = Group.objects.get(
id=settings.SITH_GROUP_OLD_SUBSCRIBERS_ID
)
_product_recipe = product_recipe.extend(product_type=baker.make(ProductType))
cls.gift = price_recipe.make(amount=-1.5, groups=[subscriber_group])
cls.gift = price_recipe.make(
amount=-1.5, groups=[subscriber_group], product=_product_recipe.make()
)
cls.beer = price_recipe.make(
groups=[subscriber_group],
amount=1.5,
product=product_recipe.make(limit_age=18),
product=_product_recipe.make(limit_age=18),
)
cls.beer_tap = price_recipe.make(
groups=[subscriber_group],
amount=1.5,
product=product_recipe.make(limit_age=18, tray=True),
product=_product_recipe.make(limit_age=18, tray=True),
)
cls.snack = price_recipe.make(
groups=[subscriber_group, old_subscriber_group],
amount=1.5,
product=product_recipe.make(limit_age=0),
product=_product_recipe.make(limit_age=0),
)
cls.stamps = price_recipe.make(
groups=[subscriber_group],
amount=1.5,
product=product_recipe.make(limit_age=0),
product=_product_recipe.make(limit_age=0),
)
ReturnableProduct.objects.all().delete()
cls.cons = price_recipe.make(amount=1, groups=[subscriber_group])
cls.dcons = price_recipe.make(amount=-1, groups=[subscriber_group])
cls.cons = price_recipe.make(
amount=1, groups=[subscriber_group], product=_product_recipe.make()
)
cls.dcons = price_recipe.make(
amount=-1, groups=[subscriber_group], product=_product_recipe.make()
)
baker.make(
ReturnableProduct,
product=cls.cons.product,
@@ -575,18 +583,17 @@ class TestCounterClick(TestFullClickBase):
group = baker.make(Group)
customer = baker.make(Customer)
group.users.add(customer.user)
_product_recipe = product_recipe.extend(
counters=[counter], product_type=baker.make(ProductType)
)
price_recipe.make(
_quantity=2,
product=iter(
product_recipe.make(archived=True, counters=[counter], _quantity=2)
),
product=iter(_product_recipe.make(archived=True, _quantity=2)),
groups=[group],
)
unarchived_prices = price_recipe.make(
_quantity=2,
product=iter(
product_recipe.make(archived=False, counters=[counter], _quantity=2)
),
product=iter(_product_recipe.make(archived=False, _quantity=2)),
groups=[group],
)
customer_prices = counter.get_prices_for(customer)