master plan implemenattion

This commit is contained in:
IGNY8 VPS (Salman)
2025-12-30 08:51:31 +00:00
parent 96aaa4151a
commit 2af7bb725f
10 changed files with 900 additions and 26 deletions

View File

@@ -143,6 +143,83 @@ class UsageLimitsSerializer(serializers.Serializer):
limits: LimitCardSerializer = LimitCardSerializer(many=True)
class AccountPaymentMethodSerializer(serializers.Serializer):
"""
Serializer for Account Payment Methods
Handles CRUD operations for account-specific payment methods
"""
id = serializers.IntegerField(read_only=True)
type = serializers.ChoiceField(
choices=[
('stripe', 'Stripe (Credit/Debit Card)'),
('paypal', 'PayPal'),
('bank_transfer', 'Bank Transfer (Manual)'),
('local_wallet', 'Local Wallet (Manual)'),
('manual', 'Manual Payment'),
]
)
display_name = serializers.CharField(max_length=100)
is_default = serializers.BooleanField(default=False)
is_enabled = serializers.BooleanField(default=True)
is_verified = serializers.BooleanField(read_only=True, default=False)
instructions = serializers.CharField(required=False, allow_blank=True, default='')
metadata = serializers.JSONField(required=False, default=dict)
created_at = serializers.DateTimeField(read_only=True)
updated_at = serializers.DateTimeField(read_only=True)
def validate_display_name(self, value):
"""Validate display_name uniqueness per account"""
account = self.context.get('account')
instance = getattr(self, 'instance', None)
if account:
from igny8_core.business.billing.models import AccountPaymentMethod
existing = AccountPaymentMethod.objects.filter(
account=account,
display_name=value
)
if instance:
existing = existing.exclude(pk=instance.pk)
if existing.exists():
raise serializers.ValidationError(
f"A payment method with name '{value}' already exists for this account."
)
return value
def create(self, validated_data):
from igny8_core.business.billing.models import AccountPaymentMethod
account = self.context.get('account')
if not account:
raise serializers.ValidationError("Account context is required")
# If this is marked as default, unset other defaults
if validated_data.get('is_default', False):
AccountPaymentMethod.objects.filter(
account=account,
is_default=True
).update(is_default=False)
return AccountPaymentMethod.objects.create(
account=account,
**validated_data
)
def update(self, instance, validated_data):
from igny8_core.business.billing.models import AccountPaymentMethod
# If this is marked as default, unset other defaults
if validated_data.get('is_default', False) and not instance.is_default:
AccountPaymentMethod.objects.filter(
account=instance.account,
is_default=True
).exclude(pk=instance.pk).update(is_default=False)
for attr, value in validated_data.items():
setattr(instance, attr, value)
instance.save()
return instance
class AIModelConfigSerializer(serializers.Serializer):
"""
Serializer for AI Model Configuration (Read-Only API)

View File

@@ -39,6 +39,7 @@ class ClustersResource(resources.ModelResource):
class ClustersAdmin(ImportExportMixin, SiteSectorAdminMixin, Igny8ModelAdmin):
resource_class = ClustersResource
list_display = ['name', 'site', 'sector', 'keywords_count', 'volume', 'status', 'created_at']
list_select_related = ['site', 'sector', 'account']
list_filter = [
('status', ChoicesDropdownFilter),
('site', RelatedDropdownFilter),
@@ -97,6 +98,7 @@ class KeywordsAdmin(ImportExportMixin, SiteSectorAdminMixin, Igny8ModelAdmin):
resource_class = KeywordsResource
list_display = ['keyword', 'seed_keyword', 'site', 'sector', 'cluster', 'volume', 'difficulty', 'country', 'status', 'created_at']
list_editable = ['status'] # Enable inline editing for status
list_select_related = ['site', 'sector', 'cluster', 'seed_keyword', 'seed_keyword__industry', 'seed_keyword__sector', 'account']
list_filter = [
('status', ChoicesDropdownFilter),
('country', ChoicesDropdownFilter),
@@ -107,7 +109,7 @@ class KeywordsAdmin(ImportExportMixin, SiteSectorAdminMixin, Igny8ModelAdmin):
('difficulty', RangeNumericFilter),
('created_at', RangeDateFilter),
]
search_fields = ['keyword', 'seed_keyword__keyword']
search_fields = ['seed_keyword__keyword']
ordering = ['-created_at']
autocomplete_fields = ['cluster', 'site', 'sector', 'seed_keyword']
actions = [
@@ -218,6 +220,7 @@ class ContentIdeasResource(resources.ModelResource):
class ContentIdeasAdmin(ImportExportMixin, SiteSectorAdminMixin, Igny8ModelAdmin):
resource_class = ContentIdeasResource
list_display = ['idea_title', 'site', 'sector', 'description_preview', 'content_type', 'content_structure', 'status', 'keyword_cluster', 'estimated_word_count', 'created_at']
list_select_related = ['site', 'sector', 'keyword_cluster', 'account']
list_filter = [
('status', ChoicesDropdownFilter),
('content_type', ChoicesDropdownFilter),