exclude products over clic limit from eboutic

This commit is contained in:
imperosol
2026-05-14 12:28:59 +02:00
parent 2d135cdf6b
commit 62900b8c2e
7 changed files with 29 additions and 21 deletions
+6 -1
View File
@@ -29,7 +29,12 @@
align-items: center; align-items: center;
gap: 20px; gap: 20px;
&.clickable:hover { &:disabled {
background-color: darken($primary-neutral-light-color, 5%);
opacity: 65%;
}
&.clickable:not(:disabled):hover {
background-color: darken($primary-neutral-light-color, 5%); background-color: darken($primary-neutral-light-color, 5%);
} }
+1 -1
View File
@@ -23,7 +23,7 @@
border-radius: 5px; border-radius: 5px;
color: black; color: black;
&:hover { &:not(.link-like):not(:disabled):hover {
background: hsl(0, 0%, 83%); background: hsl(0, 0%, 83%);
} }
} }
+3 -11
View File
@@ -22,7 +22,7 @@ import string
from datetime import date, datetime, timedelta from datetime import date, datetime, timedelta
from datetime import timezone as tz from datetime import timezone as tz
from decimal import Decimal from decimal import Decimal
from typing import TYPE_CHECKING, Literal, Self from typing import Literal, Self
from dict2xml import dict2xml from dict2xml import dict2xml
from django.conf import settings from django.conf import settings
@@ -48,9 +48,6 @@ from core.utils import get_start_of_semester
from counter.fields import CurrencyField from counter.fields import CurrencyField
from subscription.models import Subscription from subscription.models import Subscription
if TYPE_CHECKING:
from collections.abc import Sequence
def get_eboutic() -> Counter: def get_eboutic() -> Counter:
return Counter.objects.filter(type="EBOUTIC").order_by("id").first() return Counter.objects.filter(type="EBOUTIC").order_by("id").first()
@@ -773,10 +770,8 @@ class Counter(models.Model):
# but they share the same primary key # but they share the same primary key
return self.type == "BAR" and any(b.pk == customer.pk for b in self.barmen_list) return self.type == "BAR" and any(b.pk == customer.pk for b in self.barmen_list)
def get_prices_for( def get_prices_for(self, customer: Customer) -> PriceQuerySet:
self, customer: Customer, *, order_by: Sequence[str] | None = None return (
) -> list[Price]:
qs = (
Price.objects.filter( Price.objects.filter(
product__counters=self, product__product_type__isnull=False product__counters=self, product__product_type__isnull=False
) )
@@ -784,9 +779,6 @@ class Counter(models.Model):
.select_related("product", "product__product_type") .select_related("product", "product__product_type")
.prefetch_related("groups") .prefetch_related("groups")
) )
if order_by:
qs = qs.order_by(*order_by)
return list(qs)
class CounterSellers(models.Model): class CounterSellers(models.Model):
+1 -1
View File
@@ -596,7 +596,7 @@ class TestCounterClick(TestFullClickBase):
product=iter(_product_recipe.make(archived=False, _quantity=2)), product=iter(_product_recipe.make(archived=False, _quantity=2)),
groups=[group], groups=[group],
) )
customer_prices = counter.get_prices_for(customer) customer_prices = list(counter.get_prices_for(customer))
assert unarchived_prices == customer_prices assert unarchived_prices == customer_prices
+1 -1
View File
@@ -103,7 +103,7 @@ class CounterClick(
): ):
return redirect(obj) # Redirect to counter return redirect(obj) # Redirect to counter
self.prices = obj.get_prices_for(self.customer) self.prices = list(obj.get_prices_for(self.customer))
return super().dispatch(request, *args, **kwargs) return super().dispatch(request, *args, **kwargs)
+5 -1
View File
@@ -187,9 +187,10 @@
{% for price in prices %} {% for price in prices %}
<button <button
id="{{ price.id }}" id="{{ price.id }}"
class="card product-button clickable shadow" class="card clickable shadow"
:class="{selected: basket.some((i) => i.priceId === {{ price.id }})}" :class="{selected: basket.some((i) => i.priceId === {{ price.id }})}"
@click='addFromCatalog({{ price.id }}, {{ price.full_label|tojson }}, {{ price.amount }})' @click='addFromCatalog({{ price.id }}, {{ price.full_label|tojson }}, {{ price.amount }})'
{% if price.sold_out %}disabled{% endif %}
> >
{% if price.product.icon %} {% if price.product.icon %}
<img <img
@@ -202,6 +203,9 @@
{% endif %} {% endif %}
<div class="card-content"> <div class="card-content">
<h4 class="card-title">{{ price.full_label }}</h4> <h4 class="card-title">{{ price.full_label }}</h4>
{% if price.sold_out -%}
<p><em>{% trans %}Product sold out{% endtrans %}</em></p>
{%- endif %}
<p>{{ price.amount }} €</p> <p>{{ price.amount }} €</p>
</div> </div>
</button> </button>
+12 -5
View File
@@ -33,7 +33,7 @@ from django.contrib.auth.mixins import LoginRequiredMixin
from django.contrib.messages.views import SuccessMessageMixin from django.contrib.messages.views import SuccessMessageMixin
from django.core.exceptions import SuspiciousOperation, ValidationError from django.core.exceptions import SuspiciousOperation, ValidationError
from django.db import DatabaseError, transaction from django.db import DatabaseError, transaction
from django.db.models import Subquery from django.db.models import Exists, OuterRef, Subquery
from django.db.models.fields import forms from django.db.models.fields import forms
from django.db.utils import cached_property from django.db.utils import cached_property
from django.http import HttpResponse from django.http import HttpResponse
@@ -92,7 +92,9 @@ class EbouticMainView(LoginRequiredMixin, FormView):
kwargs["form_kwargs"] = { kwargs["form_kwargs"] = {
"customer": self.customer, "customer": self.customer,
"counter": get_eboutic(), "counter": get_eboutic(),
"allowed_prices": {price.id: price for price in self.prices}, "allowed_prices": {
price.id: price for price in self.prices if not price.sold_out
},
} }
return kwargs return kwargs
@@ -118,9 +120,14 @@ class EbouticMainView(LoginRequiredMixin, FormView):
@cached_property @cached_property
def prices(self) -> list[Price]: def prices(self) -> list[Price]:
return get_eboutic().get_prices_for( eboutic = get_eboutic()
self.customer, sold_out_subquery = ~Exists(
order_by=["product__product_type__order", "product_id", "amount"], eboutic.products.under_clic_limit().filter(id=OuterRef("product_id"))
)
return list(
eboutic.get_prices_for(self.customer)
.annotate(sold_out=sold_out_subquery)
.order_by("product__product_type__order", "product_id", "amount")
) )
@cached_property @cached_property