winofy-backend/apps/catalog/views.py
Ali Asadi 52adc732fa Initial Winofy backend: marketplace core (no payment integration)
Django 6 + DRF resource server against the Gooyal accounts OAuth2 service,
matching the Winsoo ecosystem's conventions. Covers locations, stores,
catalog, cart, checkout/orders (with the multi-store-cart split and the
status stepper), reviews, and notifications, plus a demo-data seed command.

Payment integration (wallet debits, online gateway, seller payouts) is
intentionally left out here — see feature/payment.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-10 14:03:15 +03:30

78 lines
2.8 KiB
Python

from django.db.models import Q
from rest_framework import mixins, viewsets
from rest_framework.decorators import action
from rest_framework.permissions import AllowAny, IsAuthenticated
from rest_framework.response import Response
from apps.core.permissions import IsStoreOwner
from apps.stores.models import Store
from .models import Product, ProductCategory
from .serializers import (
ProductCategorySerializer,
ProductDetailSerializer,
ProductListSerializer,
SellerProductSerializer,
StockAdjustSerializer,
)
class ProductCategoryViewSet(mixins.ListModelMixin, viewsets.GenericViewSet):
schema_tags = ['Catalog']
permission_classes = [AllowAny]
serializer_class = ProductCategorySerializer
queryset = ProductCategory.objects.all()
class ProductViewSet(mixins.ListModelMixin, mixins.RetrieveModelMixin, viewsets.GenericViewSet):
"""Customer-facing product browsing (store page, product detail, search)."""
schema_tags = ['Catalog']
permission_classes = [AllowAny]
queryset = Product.objects.filter(
is_active=True, store__status=Store.Status.APPROVED,
).select_related('store', 'category')
def get_serializer_class(self):
if self.action == 'retrieve':
return ProductDetailSerializer
return ProductListSerializer
def get_queryset(self):
queryset = super().get_queryset()
store_uuid = self.request.query_params.get('store')
if store_uuid:
queryset = queryset.filter(store__uuid=store_uuid)
category_uuid = self.request.query_params.get('category')
if category_uuid:
queryset = queryset.filter(category__uuid=category_uuid)
search = self.request.query_params.get('search')
if search:
queryset = queryset.filter(Q(name__icontains=search) | Q(description__icontains=search))
return queryset
class SellerProductViewSet(viewsets.ModelViewSet):
"""Seller's own product management (S06 list, S07 add, S08 inventory)."""
schema_tags = ['Seller · Products']
permission_classes = [IsAuthenticated, IsStoreOwner]
serializer_class = SellerProductSerializer
def get_queryset(self):
if getattr(self, 'swagger_fake_view', False):
return Product.objects.none()
return Product.objects.filter(store=self.request.user.store).select_related('category')
@action(detail=True, methods=['patch'], url_path='stock')
def adjust_stock(self, request, pk=None):
product = self.get_object()
serializer = StockAdjustSerializer(data=request.data)
serializer.is_valid(raise_exception=True)
product.stock_quantity = serializer.validated_data['stock_quantity']
product.save(update_fields=['stock_quantity', 'updated_at'])
return Response(SellerProductSerializer(product).data)