feat: implement category management system and product-to-category mapping functionality
Some checks failed
Deploy Beta (NATIVE) / deploy (push) Failing after 22s

This commit is contained in:
vickytechkey 2026-08-16 15:29:44 +05:30
parent e82dc2f555
commit 80ea0858ee
4 changed files with 105 additions and 1 deletions

View file

@ -79,6 +79,21 @@ class WalletTransactionSerializer(serializers.ModelSerializer):
model = WalletTransaction
fields = ['id', 'wallet', 'amount', 'tx_type', 'status']
class CategorySerializer(serializers.ModelSerializer):
subcategories = serializers.SerializerMethodField()
class Meta:
model = Category
fields = ['id', 'name', 'slug', 'is_active', 'sort_order', 'parent', 'subcategories']
def get_subcategories(self, obj):
# We perform filtering inside Python or basic query to fetch subcategories
if obj.parent_id is None:
# Query subcategories where parent matches obj
subs = Category.objects.filter(parent=obj)
return CategorySerializer(subs, many=True).data
return []
class CustomerProfileSerializer(serializers.ModelSerializer):
name = serializers.CharField(read_only=True)
email = serializers.CharField(read_only=True)

View file

@ -1,5 +1,5 @@
from django.urls import path
from crm.views import auth_views, seller_views, customer_views, product_views, wallet_views, debug_views, dashboard_views
from crm.views import auth_views, seller_views, customer_views, product_views, wallet_views, debug_views, dashboard_views, category_views
urlpatterns = [
# Auth
@ -36,8 +36,13 @@ urlpatterns = [
path('products/<int:pk>/approve/', product_views.approve_product, name='approve_product'),
path('products/<int:pk>/hold/', product_views.hold_product, name='hold_product'),
path('products/<int:pk>/reject/', product_views.reject_product, name='reject_product'),
path('products/<int:pk>/map-category/', category_views.map_product_category, name='map_product_category'),
path('products/<int:pk>/', product_views.delete_product, name='delete_product'),
# Categories
path('categories/', category_views.list_categories, name='list_categories'),
path('categories/create/', category_views.create_category, name='create_category'),
# Wallet / Withdrawals
path('wallets/withdrawals/', wallet_views.list_withdrawals, name='list_withdrawals'),
path('wallets/withdrawals/<int:pk>/approve/', wallet_views.approve_withdrawal, name='approve_withdrawal'),

View file

@ -0,0 +1,69 @@
from rest_framework import status
from rest_framework.decorators import api_view, permission_classes
from rest_framework.response import Response
from django.utils.text import slugify
from crm.permissions import IsCRMAdmin
from customer_models.models import Category
from seller_models.models import Product
from crm.serializers import CategorySerializer
from crm.views.product_views import log_product_action
@api_view(['GET'])
@permission_classes([IsCRMAdmin])
def list_categories(request):
# Only return top-level categories (parent is null)
categories = Category.objects.filter(parent__isnull=True)
serializer = CategorySerializer(categories, many=True)
return Response(serializer.data)
@api_view(['POST'])
@permission_classes([IsCRMAdmin])
def create_category(request):
name = request.data.get('name')
parent_id = request.data.get('parent')
if not name:
return Response({"detail": "Name is required"}, status=400)
slug = request.data.get('slug', slugify(name))
# Check if category with this slug already exists
if Category.objects.filter(slug=slug).exists():
slug = f"{slug}-{Category.objects.filter(slug__startswith=slug).count() + 1}"
parent = None
if parent_id:
try:
parent = Category.objects.get(pk=parent_id)
except Category.DoesNotExist:
return Response({"detail": "Parent category not found"}, status=404)
# Save category to database
category = Category.objects.create(
name=name,
slug=slug,
parent=parent,
is_active=True
)
serializer = CategorySerializer(category)
return Response(serializer.data, status=201)
@api_view(['POST'])
@permission_classes([IsCRMAdmin])
def map_product_category(request, pk):
try:
product = Product.objects.get(pk=pk)
except Product.DoesNotExist:
return Response({"detail": "Product not found"}, status=404)
category_val = request.data.get('category')
if not category_val:
return Response({"detail": "Category value is required"}, status=400)
# Save category field (holds name/slug of the category or subcategory)
product.category = category_val
product.save()
log_product_action(request.user, 'map_category', product.id, {"title": product.name, "category": category_val})
return Response({"message": f"Product mapped under category '{category_val}' successfully"})

View file

@ -1,5 +1,20 @@
from django.db import models
class Category(models.Model):
name = models.CharField(max_length=100)
slug = models.SlugField(max_length=100, unique=True, blank=True)
is_active = models.BooleanField(default=True)
sort_order = models.IntegerField(default=0)
parent = models.ForeignKey('self', on_delete=models.SET_NULL, null=True, blank=True, related_name='subcategories', db_column='parent_id')
class Meta:
managed = False
db_table = 'products_category'
ordering = ['sort_order', 'name']
def __str__(self):
return self.name
class CustomerProfile(models.Model):
user_id = models.IntegerField(unique=True)
phone = models.CharField(max_length=20, blank=True, null=True)