Files
smoothschedule/smoothschedule/analytics/serializers.py
poduck e4ad7fca87 feat: Plan-based feature permissions and quota enforcement
Backend:
- Add HasQuota() permission factory for quota limits (resources, users, services, appointments, email templates, automated tasks)
- Add HasFeaturePermission() factory for feature-based permissions (SMS, masked calling, custom domains, white label, plugins, webhooks, calendar sync, analytics)
- Add has_feature() method to Tenant model for flexible permission checking
- Add new tenant permission fields: can_create_plugins, can_use_webhooks, can_use_calendar_sync, can_export_data
- Create Data Export API with CSV/JSON support for appointments, customers, resources, services
- Create Analytics API with dashboard, appointments, revenue endpoints
- Add calendar sync views and URL configuration

Frontend:
- Add usePlanFeatures hook for checking feature availability
- Add UpgradePrompt components (inline, banner, overlay variants)
- Add LockedSection wrapper and LockedButton for feature gating
- Update settings pages with permission checks

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-12-02 11:21:11 -05:00

74 lines
2.8 KiB
Python

"""
Analytics Serializers
Read-only serializers for analytics data.
"""
from rest_framework import serializers
class DashboardStatsSerializer(serializers.Serializer):
"""Serializer for dashboard summary statistics"""
total_appointments_this_month = serializers.IntegerField()
total_appointments_all_time = serializers.IntegerField()
active_resources_count = serializers.IntegerField()
active_services_count = serializers.IntegerField()
upcoming_appointments_count = serializers.IntegerField()
average_appointment_duration_minutes = serializers.FloatField()
peak_booking_day = serializers.CharField()
peak_booking_hour = serializers.IntegerField()
period = serializers.DictField()
class ServiceBreakdownSerializer(serializers.Serializer):
"""Service breakdown statistics"""
service_id = serializers.IntegerField()
service_name = serializers.CharField()
count = serializers.IntegerField()
revenue_cents = serializers.IntegerField(required=False, allow_null=True)
class ResourceBreakdownSerializer(serializers.Serializer):
"""Resource breakdown statistics"""
resource_id = serializers.IntegerField()
resource_name = serializers.CharField()
count = serializers.IntegerField()
class StatusBreakdownSerializer(serializers.Serializer):
"""Status breakdown for appointments"""
confirmed = serializers.IntegerField()
cancelled = serializers.IntegerField()
no_show = serializers.IntegerField()
class DailyBreakdownSerializer(serializers.Serializer):
"""Daily breakdown of analytics"""
date = serializers.DateField()
count = serializers.IntegerField(required=False)
revenue_cents = serializers.IntegerField(required=False, allow_null=True)
transaction_count = serializers.IntegerField(required=False)
status_breakdown = StatusBreakdownSerializer(required=False)
class AppointmentAnalyticsSerializer(serializers.Serializer):
"""Serializer for appointment analytics response"""
total = serializers.IntegerField()
by_status = StatusBreakdownSerializer()
by_service = ServiceBreakdownSerializer(many=True)
by_resource = ResourceBreakdownSerializer(many=True)
daily_breakdown = DailyBreakdownSerializer(many=True)
booking_trend_percent = serializers.FloatField()
cancellation_rate_percent = serializers.FloatField()
no_show_rate_percent = serializers.FloatField()
period_days = serializers.IntegerField()
class RevenueAnalyticsSerializer(serializers.Serializer):
"""Serializer for revenue analytics response"""
total_revenue_cents = serializers.IntegerField()
transaction_count = serializers.IntegerField()
average_transaction_value_cents = serializers.IntegerField()
by_service = ServiceBreakdownSerializer(many=True)
daily_breakdown = DailyBreakdownSerializer(many=True)
period_days = serializers.IntegerField()