bottleneckcrm/backend/test_crm_seller_products.py
vickytechkey a4e46dc22c
All checks were successful
Deploy Beta (NATIVE) / deploy (push) Successful in 2m8s
feat: add sellers app, database router, serializers, views, and frontend pages
2026-11-08 17:09:07 +05:30

307 lines
11 KiB
Python

import os
import sys
from unittest.mock import MagicMock
# Mock celery before importing settings
sys.modules['celery'] = MagicMock()
sys.modules['celery.schedules'] = MagicMock()
sys.modules['django_celery_beat'] = MagicMock()
sys.modules['drf_spectacular'] = MagicMock()
sys.modules['drf_spectacular.extensions'] = MagicMock()
sys.path.insert(0, 'D:/Tradhox_workspace/Django-CRM/backend')
os.environ['DJANGO_SETTINGS_MODULE'] = 'crm.settings'
import django
from django.conf import settings
# Override settings for standalone unit test
settings.DATABASES = {
'default': {
'ENGINE': 'django.db.backends.sqlite3',
'NAME': ':memory:',
},
'seller_db': {
'ENGINE': 'django.db.backends.sqlite3',
'NAME': ':memory:',
},
'product_db': {
'ENGINE': 'django.db.backends.sqlite3',
'NAME': ':memory:',
},
'customer_db': {
'ENGINE': 'django.db.backends.sqlite3',
'NAME': ':memory:',
},
}
settings.REST_FRAMEWORK = {
'DEFAULT_AUTHENTICATION_CLASSES': [],
'DEFAULT_PERMISSION_CLASSES': [],
}
settings.DATABASE_ROUTERS = ['crm.db_router.CRMDatabaseRouter']
settings.AUTH_USER_MODEL = 'auth.User'
settings.INSTALLED_APPS = [
'django.contrib.contenttypes',
'django.contrib.auth',
'rest_framework',
'sellers',
]
django.setup()
from sellers.models import SupplierProfile, Product, BulkUploadLog, SellerOrder, Wallet
from sellers.serializers import (
SupplierProfileListSerializer,
SupplierProfileDetailSerializer,
ProductSerializer
)
from crm.db_router import CRMDatabaseRouter
# 1. Test Router mappings
router = CRMDatabaseRouter()
assert router.db_for_read(Product) == 'product_db', f"Product should route to product_db, got {router.db_for_read(Product)}"
assert router.db_for_read(BulkUploadLog) == 'product_db', f"BulkUploadLog should route to product_db, got {router.db_for_read(BulkUploadLog)}"
assert router.db_for_read(SellerOrder) == 'customer_db', f"SellerOrder should route to customer_db, got {router.db_for_read(SellerOrder)}"
assert router.db_for_read(Wallet) == 'customer_db', f"Wallet should route to customer_db, got {router.db_for_read(Wallet)}"
assert router.db_for_read(SupplierProfile) == 'seller_db', f"SupplierProfile should route to seller_db, got {router.db_for_read(SupplierProfile)}"
print("CRMDatabaseRouter checks passed!")
# 2. Create tables in test DBs
from django.db import connections
def create_table_product():
with connections['product_db'].cursor() as c:
c.execute("""
CREATE TABLE api_product (
id INTEGER PRIMARY KEY AUTOINCREMENT,
supplier_id INTEGER,
title VARCHAR(255),
category VARCHAR(100),
price DECIMAL(10, 2),
stock INTEGER,
sku VARCHAR(100),
image TEXT,
is_active BOOLEAN,
status VARCHAR(50),
compare_at_price DECIMAL(10, 2),
description TEXT,
is_gi_tagged BOOLEAN,
gi_tag_name VARCHAR(200),
is_odop BOOLEAN,
odop_district VARCHAR(200),
is_sustainable BOOLEAN,
sustainable_type VARCHAR(200),
geographical_origin VARCHAR(255),
statutory_certifications TEXT,
provenance_story TEXT,
coordinates VARCHAR(100),
track_inventory BOOLEAN,
shipping_profile VARCHAR(100),
processing_days INTEGER,
package_weight REAL,
upload_source VARCHAR(50),
rejection_reason TEXT,
additional_images TEXT,
video_url VARCHAR(200),
view_360_url VARCHAR(200)
)
""")
def create_table_seller():
with connections['seller_db'].cursor() as c:
c.execute("""
CREATE TABLE api_supplierprofile (
id INTEGER PRIMARY KEY,
user_id INTEGER UNIQUE,
phone VARCHAR(20),
phone_verified BOOLEAN,
email_verified BOOLEAN,
gstin VARCHAR(15),
is_gstin_verified BOOLEAN,
pan_number VARCHAR(20),
is_pan_verified BOOLEAN,
verified_pan_name VARCHAR(255),
verified_gst_name VARCHAR(255),
is_verified BOOLEAN,
business_type VARCHAR(50),
store_slug VARCHAR(255),
aadhar_file VARCHAR(255),
pan_file VARCHAR(255),
aadhar_s3_key VARCHAR(255),
pan_s3_key VARCHAR(255),
store_name VARCHAR(255),
store_logo TEXT,
logo_s3_key VARCHAR(255),
business_bio TEXT,
street VARCHAR(255),
city VARCHAR(100),
state VARCHAR(100),
pincode VARCHAR(20),
latitude REAL,
longitude REAL,
status VARCHAR(50),
submitted_at DATETIME,
approved_at DATETIME,
approved_by VARCHAR(150),
rejected_reason TEXT,
is_profile_complete BOOLEAN,
pickup_code VARCHAR(100),
account_holder_name VARCHAR(255),
account_number VARCHAR(50),
ifsc_code VARCHAR(20),
bank_name VARCHAR(255),
is_bank_verified BOOLEAN,
tax_mode VARCHAR(20)
)
""")
def create_table_customer():
with connections['customer_db'].cursor() as c:
c.execute("""
CREATE TABLE api_order (
id INTEGER PRIMARY KEY AUTOINCREMENT,
order_id VARCHAR(100),
customer VARCHAR(255),
item VARCHAR(255),
quantity INTEGER,
total DECIMAL(12, 2),
status VARCHAR(50),
carrier VARCHAR(100),
tracking VARCHAR(100),
date DATE,
supplier_id INTEGER,
payment_mode VARCHAR(20),
eta VARCHAR(50),
expected_delivery_date VARCHAR(100),
pickup_id VARCHAR(100),
pickup_payload TEXT
)
""")
c.execute("""
CREATE TABLE api_wallet (
id INTEGER PRIMARY KEY AUTOINCREMENT,
supplier_id INTEGER UNIQUE,
outstanding DECIMAL(12, 2),
withdrawn DECIMAL(12, 2)
)
""")
create_table_product()
create_table_seller()
create_table_customer()
# Create SupplierProfile with id=46, user_id=28
seller = SupplierProfile.objects.create(
id=46,
user_id=28,
store_name="vignesh store",
phone="9600494039",
status="approved"
)
# Create Product with supplier_id=28 (which is seller.user_id)
product = Product.objects.create(
id=20,
supplier_id=28,
title="Pure Kanchipuram Mulberry Silk Saree - Crimson Maroon & Gold Zari",
category="Clothing & Textiles",
price=14500.00,
stock=8,
sku="TRDX-KSS-960049",
is_gi_tagged=True,
gi_tag_name="Kancheepuram Silk (GI Application #26)",
is_odop=True,
odop_district="Kanchipuram, Tamil Nadu",
is_sustainable=True,
sustainable_type="Handloom Organic Mulberry Silk & Eco-dyes",
geographical_origin="Kanchipuram, Tamil Nadu, India",
statutory_certifications="GI Tag #26 Registered, Silk Mark Certified, Handloom Mark India",
status="pending",
is_active=True
)
# Test SupplierProfileListSerializer
list_data = SupplierProfileListSerializer(seller).data
print(f"SupplierProfileListSerializer products_count: {list_data['products_count']}")
assert list_data['products_count'] == 1, f"Expected products_count 1, got {list_data['products_count']}"
# Test SupplierProfileDetailSerializer
detail_data = SupplierProfileDetailSerializer(seller).data
print(f"Detail metrics: {detail_data['metrics']}")
assert detail_data['metrics']['total_products'] == 1, f"Expected 1 total_products, got {detail_data['metrics']['total_products']}"
assert detail_data['metrics']['total_items_in_stock'] == 8, f"Expected 8 items in stock, got {detail_data['metrics']['total_items_in_stock']}"
assert len(detail_data['products']) == 1, f"Expected 1 product in products list, got {len(detail_data['products'])}"
prod_data = detail_data['products'][0]
print(f"Product in detail: ID={prod_data['id']}, title='{prod_data['title']}', is_gi_tagged={prod_data['is_gi_tagged']}, is_odop={prod_data['is_odop']}, is_sustainable={prod_data['is_sustainable']}")
assert prod_data['id'] == 20
assert prod_data['is_gi_tagged'] is True
assert prod_data['is_odop'] is True
assert prod_data['is_sustainable'] is True
print("ALL SERIALIZER AND MODEL TESTS PASSED SUCCESSFULLY!")
# 3. Test Views logic (Approve, Reject, Toggle, Edit Content)
from sellers.views import (
SellerProductApproveView,
SellerProductRejectView,
SellerProductToggleView,
SellerProductDetailView
)
from django.core.management import call_command
call_command('migrate', database='default', run_syncdb=True, verbosity=0)
from rest_framework.test import APIRequestFactory, force_authenticate
from django.contrib.auth.models import User
factory = APIRequestFactory()
admin_user = User.objects.create_user(username='admin', email='admin@tradhox.com')
# Test Approve
req = factory.post(f"/api/sellers/46/products/20/approve/")
force_authenticate(req, user=admin_user)
resp = SellerProductApproveView.as_view()(req, pk=46, product_id=20)
assert resp.status_code == 200, f"Expected 200, got {resp.status_code}: {resp.data}"
p = Product.objects.using('product_db').get(pk=20)
assert p.status == 'approved'
assert p.is_active is True
print("SellerProductApproveView passed!")
# Test Reject
req = factory.post(f"/api/sellers/46/products/20/reject/", {"reason": "Quality check required"}, format="json")
force_authenticate(req, user=admin_user)
resp = SellerProductRejectView.as_view()(req, pk=46, product_id=20)
assert resp.status_code == 200
p = Product.objects.using('product_db').get(pk=20)
assert p.status == 'rejected'
assert p.is_active is False
assert p.rejection_reason == "Quality check required"
print("SellerProductRejectView passed!")
# Test Toggle
req = factory.post(f"/api/sellers/46/products/20/toggle/", {"is_active": True, "status": "approved"}, format="json")
force_authenticate(req, user=admin_user)
resp = SellerProductToggleView.as_view()(req, pk=46, product_id=20)
assert resp.status_code == 200
p = Product.objects.using('product_db').get(pk=20)
assert p.is_active is True
assert p.status == 'approved'
print("SellerProductToggleView passed!")
# Test Detail PATCH
req = factory.patch(f"/api/sellers/46/products/20/", {
"price": 15200.00,
"stock": 12,
"is_odop": True,
"odop_district": "Kanchipuram District",
"geographical_origin": "Kanchipuram, Tamil Nadu"
}, format="json")
force_authenticate(req, user=admin_user)
resp = SellerProductDetailView.as_view()(req, pk=46, product_id=20)
assert resp.status_code == 200
p = Product.objects.using('product_db').get(pk=20)
assert float(p.price) == 15200.00
assert p.stock == 12
assert p.odop_district == "Kanchipuram District"
print("SellerProductDetailView PATCH passed!")
print("ALL VIEWS AND API ENDPOINT TESTS PASSED SUCCESSFULLY!")