feat: public StorefrontDetailView for customer store URL and products
All checks were successful
Deploy Beta (NATIVE) / deploy (push) Successful in 35s

This commit is contained in:
vickytechkey 2026-10-17 16:19:04 +05:30
parent 6fee9fc665
commit 4589b86f1d
2 changed files with 72 additions and 1 deletions

View file

@ -5,7 +5,8 @@ from .views import (
RegisterView, LoginView, LogoutView, VerifyOtpView, ProfileView,
ProductViewSet, BulkUploadView, BulkUploadLogsView, BulkUploadErrorReportView, OrderViewSet, ReturnRequestViewSet,
WalletView, WithdrawView, SubmitGstinView, PresignedUrlView, MockUploadView, MockDownloadView,
UploadEAadhaarView, VerifyPANView, VerifyBankView, SendWhatsAppOtpView, SendEmailOtpView, ProductSearchView, DashboardStatsView
UploadEAadhaarView, VerifyPANView, VerifyBankView, SendWhatsAppOtpView, SendEmailOtpView, ProductSearchView, DashboardStatsView,
StorefrontDetailView
)
from .logs_views import LogsView, LogStatsView, LogClearView
@ -64,5 +65,9 @@ urlpatterns = [
path('shipping/reverse/label/', ReverseLabelView.as_view(), name='shipping-reverse-label'),
path('shipping/reverse/update-qc/', ReverseUpdateQCView.as_view(), name='shipping-reverse-update-qc'),
# Public Storefront Endpoints
path('store/<str:slug>/', StorefrontDetailView.as_view(), name='store-detail'),
path('storefront/<str:slug>/', StorefrontDetailView.as_view(), name='storefront-detail'),
path('', include(router.urls)),
]

View file

@ -2641,3 +2641,69 @@ class ProductSearchView(APIView):
except Exception as err:
logger.error(f"Fallback Product Search Error: {err}", exc_info=True)
return Response({'error': str(err), 'results': [], 'count': 0}, status=status.HTTP_500_INTERNAL_SERVER_ERROR)
class StorefrontDetailView(APIView):
"""
Public API endpoint to retrieve a seller's storefront details and products by store_slug.
Accessible by customers opening tradhox.com/store/<slug>/
GET /api/store/<slug>/
GET /api/storefront/<slug>/
"""
permission_classes = [AllowAny]
def get(self, request, slug):
clean_slug = str(slug or '').strip()
if not clean_slug:
return Response({'error': 'Store slug is required'}, status=status.HTTP_400_BAD_REQUEST)
# Look up profile by store_slug, or fallback to username or store_name
profile = (
SupplierProfile.objects.filter(store_slug__iexact=clean_slug).first()
or SupplierProfile.objects.filter(user__username__iexact=clean_slug).first()
or SupplierProfile.objects.filter(store_name__iexact=clean_slug).first()
)
if not profile:
return Response({'error': 'Storefront not found', 'slug': clean_slug}, status=status.HTTP_404_NOT_FOUND)
# Build S3 / CDN URLs for banner and logo
banner_url = get_document_url(profile.banner_s3_key, request) if profile.banner_s3_key else (profile.banner_url or '')
logo_url = get_document_url(profile.logo_s3_key, request) if profile.logo_s3_key else (profile.store_logo or profile.artisan_avatar or '')
location = ", ".join([part for part in [profile.city, profile.state] if part]).strip()
if not location:
location = profile.workshop_location or "India"
# Fetch active products for this seller
products_qs = Product.objects.filter(supplier=profile.user, is_active=True).order_by('-id')
products_data = ProductSerializer(products_qs, many=True).data
# Ensure product image URLs are properly resolved
for p in products_data:
img = p.get('image')
if img and not str(img).startswith(('http://', 'https://', 'data:')):
p['image'] = get_document_url(img, request)
categories = [c.name for c in profile.categories.all()]
store_data = {
'id': profile.user.id,
'name': profile.store_name or profile.user.username,
'slug': profile.store_slug or clean_slug,
'tagline': profile.featured_tagline or profile.business_bio or "Authentic Handcrafted Treasures from Master Artisans",
'bio': profile.business_bio or "Generational master artisanal workshop preserving authentic Indian heritage crafts.",
'banner_url': banner_url,
'logo_url': logo_url,
'location': location,
'craft_lineage_years': profile.craft_lineage_years,
'is_verified': profile.is_verified or profile.status == 'approved',
'categories': categories,
'total_products': len(products_data),
}
return Response({
'status': 'success',
'store': store_data,
'products': products_data
}, status=status.HTTP_200_OK)