mirror of
https://github.com/ae-utbm/sith.git
synced 2024-12-23 00:01:16 +00:00
Pre-filter allowed products in backend for counter click
This commit is contained in:
parent
aa0a4c06cb
commit
ff475c2b87
@ -428,13 +428,6 @@ class Product(models.Model):
|
|||||||
def profit(self):
|
def profit(self):
|
||||||
return self.selling_price - self.purchase_price
|
return self.selling_price - self.purchase_price
|
||||||
|
|
||||||
def get_actual_price(self, counter: Counter, customer: Customer):
|
|
||||||
"""Return the price of the article taking into account if the customer has a special price
|
|
||||||
or not in the counter it's being purchased on"""
|
|
||||||
if counter.customer_is_barman(customer):
|
|
||||||
return self.special_selling_price
|
|
||||||
return self.selling_price
|
|
||||||
|
|
||||||
|
|
||||||
class CounterQuerySet(models.QuerySet):
|
class CounterQuerySet(models.QuerySet):
|
||||||
def annotate_has_barman(self, user: User) -> Self:
|
def annotate_has_barman(self, user: User) -> Self:
|
||||||
|
@ -53,13 +53,15 @@ class ProductForm(Form):
|
|||||||
|
|
||||||
def __init__(
|
def __init__(
|
||||||
self,
|
self,
|
||||||
|
customer: Customer,
|
||||||
|
counter: Counter,
|
||||||
|
allowed_products: list[Product],
|
||||||
*args,
|
*args,
|
||||||
customer: Customer | None = None,
|
|
||||||
counter: Counter | None = None,
|
|
||||||
**kwargs,
|
**kwargs,
|
||||||
):
|
):
|
||||||
self.customer = customer
|
self.customer = customer # Used by formset
|
||||||
self.counter = counter
|
self.counter = counter # Used by formset
|
||||||
|
self.allowed_products = allowed_products
|
||||||
super().__init__(*args, **kwargs)
|
super().__init__(*args, **kwargs)
|
||||||
|
|
||||||
def clean(self):
|
def clean(self):
|
||||||
@ -67,45 +69,27 @@ class ProductForm(Form):
|
|||||||
if len(self.errors) > 0:
|
if len(self.errors) > 0:
|
||||||
return
|
return
|
||||||
|
|
||||||
if self.customer is None or self.counter is None:
|
|
||||||
raise RuntimeError(
|
|
||||||
f"{self} has been initialized without customer or counter"
|
|
||||||
)
|
|
||||||
|
|
||||||
user = self.customer.user
|
|
||||||
|
|
||||||
# We store self.product so we can use it later on the formset validation
|
# We store self.product so we can use it later on the formset validation
|
||||||
self.product = self.counter.products.filter(id=cleaned_data["id"]).first()
|
self.product = next(
|
||||||
|
(
|
||||||
|
product
|
||||||
|
for product in self.allowed_products
|
||||||
|
if product.id == cleaned_data["id"]
|
||||||
|
),
|
||||||
|
None,
|
||||||
|
)
|
||||||
if self.product is None:
|
if self.product is None:
|
||||||
raise ValidationError(
|
raise ValidationError(
|
||||||
_(
|
_("The selected product isn't available for this user")
|
||||||
"Product %(product)s doesn't exist or isn't available on this counter"
|
|
||||||
)
|
|
||||||
% {"product": cleaned_data["id"]}
|
|
||||||
)
|
)
|
||||||
|
|
||||||
# Test alcohoolic products
|
|
||||||
if self.product.limit_age >= 18:
|
|
||||||
if not user.date_of_birth:
|
|
||||||
raise ValidationError(_("Too young for that product"))
|
|
||||||
if user.is_banned_alcohol:
|
|
||||||
raise ValidationError(_("Not allowed for that product"))
|
|
||||||
if user.date_of_birth and self.customer.user.get_age() < self.product.limit_age:
|
|
||||||
raise ValidationError(_("Too young for that product"))
|
|
||||||
|
|
||||||
if user.is_banned_counter:
|
|
||||||
raise ValidationError(_("Not allowed for that product"))
|
|
||||||
|
|
||||||
# Compute prices
|
# Compute prices
|
||||||
cleaned_data["bonus_quantity"] = 0
|
cleaned_data["bonus_quantity"] = 0
|
||||||
if self.product.tray:
|
if self.product.tray:
|
||||||
cleaned_data["bonus_quantity"] = math.floor(
|
cleaned_data["bonus_quantity"] = math.floor(
|
||||||
cleaned_data["quantity"] / Product.QUANTITY_FOR_TRAY_PRICE
|
cleaned_data["quantity"] / Product.QUANTITY_FOR_TRAY_PRICE
|
||||||
)
|
)
|
||||||
cleaned_data["unit_price"] = self.product.get_actual_price(
|
cleaned_data["total_price"] = self.product.price * (
|
||||||
self.counter, self.customer
|
|
||||||
)
|
|
||||||
cleaned_data["total_price"] = cleaned_data["unit_price"] * (
|
|
||||||
cleaned_data["quantity"] - cleaned_data["bonus_quantity"]
|
cleaned_data["quantity"] - cleaned_data["bonus_quantity"]
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -164,27 +148,62 @@ class CounterClick(CounterTabsMixin, CanViewMixin, SingleObjectMixin, FormView):
|
|||||||
pk_url_kwarg = "counter_id"
|
pk_url_kwarg = "counter_id"
|
||||||
current_tab = "counter"
|
current_tab = "counter"
|
||||||
|
|
||||||
|
def get_products(self) -> list[Product]:
|
||||||
|
"""Get all allowed products for the current customer on the current counter"""
|
||||||
|
|
||||||
|
if hasattr(self, "_products"):
|
||||||
|
return self._products
|
||||||
|
|
||||||
|
products = self.object.products.select_related("product_type").prefetch_related(
|
||||||
|
"buying_groups"
|
||||||
|
)
|
||||||
|
|
||||||
|
# Only include allowed products
|
||||||
|
if not self.customer.user.date_of_birth or self.customer.user.is_banned_alcohol:
|
||||||
|
products = products.filter(limit_age__lt=18)
|
||||||
|
else:
|
||||||
|
products = products.filter(limit_age__lte=self.customer.user.get_age())
|
||||||
|
|
||||||
|
# Compute special price for customer if he is a barmen on that bar
|
||||||
|
if self.object.customer_is_barman(self.customer):
|
||||||
|
products = products.annotate(price=F("special_selling_price"))
|
||||||
|
else:
|
||||||
|
products = products.annotate(price=F("selling_price"))
|
||||||
|
|
||||||
|
self._products = [
|
||||||
|
product
|
||||||
|
for product in products.all()
|
||||||
|
if product.can_be_sold_to(self.customer.user)
|
||||||
|
]
|
||||||
|
|
||||||
|
return self._products
|
||||||
|
|
||||||
def get_form_kwargs(self):
|
def get_form_kwargs(self):
|
||||||
kwargs = super().get_form_kwargs()
|
kwargs = super().get_form_kwargs()
|
||||||
kwargs["form_kwargs"] = {
|
kwargs["form_kwargs"] = {
|
||||||
"customer": self.customer,
|
"customer": self.customer,
|
||||||
"counter": self.object,
|
"counter": self.object,
|
||||||
|
"allowed_products": self.get_products(),
|
||||||
}
|
}
|
||||||
return kwargs
|
return kwargs
|
||||||
|
|
||||||
def dispatch(self, request, *args, **kwargs):
|
def dispatch(self, request, *args, **kwargs):
|
||||||
self.customer = get_object_or_404(Customer, user__id=self.kwargs["user_id"])
|
self.customer = get_object_or_404(Customer, user__id=self.kwargs["user_id"])
|
||||||
obj: Counter = self.get_object()
|
obj: Counter = self.get_object()
|
||||||
if not self.customer.can_buy:
|
|
||||||
raise Http404
|
if not self.customer.can_buy or self.customer.user.is_banned_counter:
|
||||||
|
return redirect(obj) # Redirect to counter
|
||||||
|
|
||||||
if obj.type != "BAR" and not request.user.is_authenticated:
|
if obj.type != "BAR" and not request.user.is_authenticated:
|
||||||
raise PermissionDenied
|
raise PermissionDenied
|
||||||
|
|
||||||
if obj.type == "BAR" and (
|
if obj.type == "BAR" and (
|
||||||
"counter_token" not in request.session
|
"counter_token" not in request.session
|
||||||
or request.session["counter_token"] != obj.token
|
or request.session["counter_token"] != obj.token
|
||||||
or len(obj.barmen_list) == 0
|
or len(obj.barmen_list) == 0
|
||||||
):
|
):
|
||||||
return redirect(obj) # Redirect to counter
|
return redirect(obj) # Redirect to counter
|
||||||
|
|
||||||
return super().dispatch(request, *args, **kwargs)
|
return super().dispatch(request, *args, **kwargs)
|
||||||
|
|
||||||
def form_valid(self, formset):
|
def form_valid(self, formset):
|
||||||
@ -207,7 +226,7 @@ class CounterClick(CounterTabsMixin, CanViewMixin, SingleObjectMixin, FormView):
|
|||||||
product=form.product,
|
product=form.product,
|
||||||
club=form.product.club,
|
club=form.product.club,
|
||||||
counter=self.object,
|
counter=self.object,
|
||||||
unit_price=form.cleaned_data["unit_price"],
|
unit_price=form.product.price,
|
||||||
quantity=form.cleaned_data["quantity"]
|
quantity=form.cleaned_data["quantity"]
|
||||||
- form.cleaned_data["bonus_quantity"],
|
- form.cleaned_data["bonus_quantity"],
|
||||||
seller=operator,
|
seller=operator,
|
||||||
@ -238,21 +257,10 @@ class CounterClick(CounterTabsMixin, CanViewMixin, SingleObjectMixin, FormView):
|
|||||||
def get_success_url(self):
|
def get_success_url(self):
|
||||||
return resolve_url(self.object)
|
return resolve_url(self.object)
|
||||||
|
|
||||||
def get_product(self, pid):
|
|
||||||
return Product.objects.filter(pk=int(pid)).first()
|
|
||||||
|
|
||||||
def get_context_data(self, **kwargs):
|
def get_context_data(self, **kwargs):
|
||||||
"""Add customer to the context."""
|
"""Add customer to the context."""
|
||||||
kwargs = super().get_context_data(**kwargs)
|
kwargs = super().get_context_data(**kwargs)
|
||||||
products = self.object.products.select_related("product_type")
|
kwargs["products"] = self.get_products()
|
||||||
|
|
||||||
# Optimisation to bulk edit prices instead of `calling get_actual_price` on everything
|
|
||||||
if self.object.customer_is_barman(self.customer):
|
|
||||||
products = products.annotate(price=F("special_selling_price"))
|
|
||||||
else:
|
|
||||||
products = products.annotate(price=F("selling_price"))
|
|
||||||
|
|
||||||
kwargs["products"] = products
|
|
||||||
kwargs["categories"] = {}
|
kwargs["categories"] = {}
|
||||||
for product in kwargs["products"]:
|
for product in kwargs["products"]:
|
||||||
if product.product_type:
|
if product.product_type:
|
||||||
|
Loading…
Reference in New Issue
Block a user