diff --git a/core/filters.py b/core/filters.py index 3122fdf9..6c57a58f 100644 --- a/core/filters.py +++ b/core/filters.py @@ -16,6 +16,7 @@ from django.db.models import ( When, Max, Prefetch, + BooleanField, ) from django.db.models.functions import Coalesce from django.utils.http import urlsafe_base64_decode @@ -92,6 +93,7 @@ class ProductFilter(FilterSet): ("price_order", "price"), ("sku", "sku"), ("?", "random"), + ("personal_order_only", "personal_order_only"), ), initial="uuid", ) @@ -279,8 +281,8 @@ class ProductFilter(FilterSet): ordering_param = self.data.get("order_by", "") if ordering_param: - order_fields = [field.strip() for field in ordering_param.split(",")] - if any(field.lstrip("-") == "rating" for field in order_fields): + order_fields_no_sign = [field.strip("-") for field in ordering_param.split(",")] + if "rating" in order_fields_no_sign: feedback_qs = ( Feedback.objects.filter(order_product__product_id=OuterRef("pk")) .values("order_product__product_id") @@ -293,6 +295,43 @@ class ProductFilter(FilterSet): Value(0, output_field=FloatField()), ) ) + + if ordering_param and any(f.lstrip("-") == "price" for f in ordering_param.split(",")): + qs = qs.annotate( + price_order=Coalesce( + Max("stocks__price"), + Value(0.0), + output_field=FloatField(), + ) + ) + + qs = qs.annotate( + personal_order_only=Case( + When(has_stock=Value(0), has_price=Value(1), then=Value(True)), + default=Value(False), + output_field=BooleanField(), + ) + ) + + requested = [part.strip() for part in ordering_param.split(",") if part.strip()] if ordering_param else [] + mapped_requested = [] + for part in requested: + desc = part.startswith("-") + key = part.lstrip("-") + if key == "price": + key = "price_order" + if key == "random": + key = "?" + mapped_requested.append(key) + continue + mapped_requested.append(f"-{key}" if desc else key) + + has_personal_in_request = any(p.lstrip("-") == "personal_order_only" for p in mapped_requested) + final_ordering = (["personal_order_only"] if not has_personal_in_request else []) + mapped_requested + + if final_ordering: + qs = qs.order_by(*final_ordering) + return qs.distinct()