Phase 3 - credts, usage, plans app pages #Migrations
This commit is contained in:
@@ -117,7 +117,7 @@ class PlanResource(resources.ModelResource):
|
||||
class Meta:
|
||||
model = Plan
|
||||
fields = ('id', 'name', 'slug', 'price', 'billing_cycle', 'max_sites', 'max_users',
|
||||
'max_keywords', 'max_content_words', 'included_credits', 'is_active', 'is_featured')
|
||||
'max_keywords', 'max_ahrefs_queries', 'included_credits', 'is_active', 'is_featured')
|
||||
export_order = fields
|
||||
import_id_fields = ('id',)
|
||||
skip_unchanged = True
|
||||
@@ -127,7 +127,7 @@ class PlanResource(resources.ModelResource):
|
||||
class PlanAdmin(ImportExportMixin, Igny8ModelAdmin):
|
||||
resource_class = PlanResource
|
||||
"""Plan admin - Global, no account filtering needed"""
|
||||
list_display = ['name', 'slug', 'price', 'billing_cycle', 'max_sites', 'max_users', 'max_keywords', 'max_content_words', 'included_credits', 'is_active', 'is_featured']
|
||||
list_display = ['name', 'slug', 'price', 'billing_cycle', 'max_sites', 'max_users', 'max_keywords', 'max_ahrefs_queries', 'included_credits', 'is_active', 'is_featured']
|
||||
list_filter = ['is_active', 'billing_cycle', 'is_internal', 'is_featured']
|
||||
search_fields = ['name', 'slug']
|
||||
readonly_fields = ['created_at']
|
||||
@@ -147,12 +147,12 @@ class PlanAdmin(ImportExportMixin, Igny8ModelAdmin):
|
||||
'description': 'Persistent limits for account-level resources'
|
||||
}),
|
||||
('Hard Limits (Persistent)', {
|
||||
'fields': ('max_keywords', 'max_clusters'),
|
||||
'fields': ('max_keywords',),
|
||||
'description': 'Total allowed - never reset'
|
||||
}),
|
||||
('Monthly Limits (Reset on Billing Cycle)', {
|
||||
'fields': ('max_content_ideas', 'max_content_words', 'max_images_basic', 'max_images_premium', 'max_image_prompts'),
|
||||
'description': 'Monthly allowances - reset at billing cycle'
|
||||
'fields': ('max_ahrefs_queries',),
|
||||
'description': 'Monthly Ahrefs keyword research queries (0 = disabled)'
|
||||
}),
|
||||
('Billing & Credits', {
|
||||
'fields': ('included_credits', 'extra_credit_price', 'allow_credit_topup', 'auto_credit_topup_threshold', 'auto_credit_topup_amount', 'credits_per_month')
|
||||
|
||||
@@ -25,18 +25,7 @@ class Command(BaseCommand):
|
||||
'max_users': 999999,
|
||||
'max_sites': 999999,
|
||||
'max_keywords': 999999,
|
||||
'max_clusters': 999999,
|
||||
'max_content_ideas': 999999,
|
||||
'monthly_word_count_limit': 999999999,
|
||||
'daily_content_tasks': 999999,
|
||||
'daily_ai_requests': 999999,
|
||||
'daily_ai_request_limit': 999999,
|
||||
'monthly_ai_credit_limit': 999999,
|
||||
'monthly_image_count': 999999,
|
||||
'daily_image_generation_limit': 999999,
|
||||
'monthly_cluster_ai_credits': 999999,
|
||||
'monthly_content_ai_credits': 999999,
|
||||
'monthly_image_ai_credits': 999999,
|
||||
'max_ahrefs_queries': 999999,
|
||||
'included_credits': 999999,
|
||||
'is_active': True,
|
||||
'features': ['ai_writer', 'image_gen', 'auto_publish', 'custom_prompts', 'unlimited'],
|
||||
|
||||
@@ -0,0 +1,100 @@
|
||||
# Generated by IGNY8 Phase 1: Simplify Credits & Limits
|
||||
# Migration: Remove unused limit fields, add Ahrefs query tracking
|
||||
# Date: January 5, 2026
|
||||
|
||||
from django.db import migrations, models
|
||||
import django.core.validators
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
"""
|
||||
Simplify the credits and limits system:
|
||||
|
||||
PLAN MODEL:
|
||||
- REMOVE: max_clusters, max_content_ideas, max_content_words,
|
||||
max_images_basic, max_images_premium, max_image_prompts
|
||||
- ADD: max_ahrefs_queries (monthly keyword research queries)
|
||||
|
||||
ACCOUNT MODEL:
|
||||
- REMOVE: usage_content_ideas, usage_content_words, usage_images_basic,
|
||||
usage_images_premium, usage_image_prompts
|
||||
- ADD: usage_ahrefs_queries
|
||||
|
||||
RATIONALE:
|
||||
All consumption is now controlled by credits only. The only non-credit
|
||||
limits are: sites, users, keywords (hard limits) and ahrefs_queries (monthly).
|
||||
"""
|
||||
|
||||
dependencies = [
|
||||
('igny8_core_auth', '0018_add_country_remove_intent_seedkeyword'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
# STEP 1: Add new Ahrefs fields FIRST (before removing old ones)
|
||||
migrations.AddField(
|
||||
model_name='plan',
|
||||
name='max_ahrefs_queries',
|
||||
field=models.IntegerField(
|
||||
default=0,
|
||||
validators=[django.core.validators.MinValueValidator(0)],
|
||||
help_text='Monthly Ahrefs keyword research queries (0 = disabled)'
|
||||
),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='account',
|
||||
name='usage_ahrefs_queries',
|
||||
field=models.IntegerField(
|
||||
default=0,
|
||||
validators=[django.core.validators.MinValueValidator(0)],
|
||||
help_text='Ahrefs queries used this month'
|
||||
),
|
||||
),
|
||||
|
||||
# STEP 2: Remove unused Plan fields
|
||||
migrations.RemoveField(
|
||||
model_name='plan',
|
||||
name='max_clusters',
|
||||
),
|
||||
migrations.RemoveField(
|
||||
model_name='plan',
|
||||
name='max_content_ideas',
|
||||
),
|
||||
migrations.RemoveField(
|
||||
model_name='plan',
|
||||
name='max_content_words',
|
||||
),
|
||||
migrations.RemoveField(
|
||||
model_name='plan',
|
||||
name='max_images_basic',
|
||||
),
|
||||
migrations.RemoveField(
|
||||
model_name='plan',
|
||||
name='max_images_premium',
|
||||
),
|
||||
migrations.RemoveField(
|
||||
model_name='plan',
|
||||
name='max_image_prompts',
|
||||
),
|
||||
|
||||
# STEP 3: Remove unused Account fields
|
||||
migrations.RemoveField(
|
||||
model_name='account',
|
||||
name='usage_content_ideas',
|
||||
),
|
||||
migrations.RemoveField(
|
||||
model_name='account',
|
||||
name='usage_content_words',
|
||||
),
|
||||
migrations.RemoveField(
|
||||
model_name='account',
|
||||
name='usage_images_basic',
|
||||
),
|
||||
migrations.RemoveField(
|
||||
model_name='account',
|
||||
name='usage_images_premium',
|
||||
),
|
||||
migrations.RemoveField(
|
||||
model_name='account',
|
||||
name='usage_image_prompts',
|
||||
),
|
||||
]
|
||||
@@ -0,0 +1,39 @@
|
||||
# Generated by Django 5.2.9 on 2026-01-06 00:11
|
||||
|
||||
import django.core.validators
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('igny8_core_auth', '0019_simplify_credits_limits'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.RemoveField(
|
||||
model_name='historicalaccount',
|
||||
name='usage_content_ideas',
|
||||
),
|
||||
migrations.RemoveField(
|
||||
model_name='historicalaccount',
|
||||
name='usage_content_words',
|
||||
),
|
||||
migrations.RemoveField(
|
||||
model_name='historicalaccount',
|
||||
name='usage_image_prompts',
|
||||
),
|
||||
migrations.RemoveField(
|
||||
model_name='historicalaccount',
|
||||
name='usage_images_basic',
|
||||
),
|
||||
migrations.RemoveField(
|
||||
model_name='historicalaccount',
|
||||
name='usage_images_premium',
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='historicalaccount',
|
||||
name='usage_ahrefs_queries',
|
||||
field=models.IntegerField(default=0, help_text='Ahrefs queries used this month', validators=[django.core.validators.MinValueValidator(0)]),
|
||||
),
|
||||
]
|
||||
@@ -108,11 +108,7 @@ class Account(SoftDeletableModel):
|
||||
tax_id = models.CharField(max_length=100, blank=True, help_text="VAT/Tax ID number")
|
||||
|
||||
# Monthly usage tracking (reset on billing cycle)
|
||||
usage_content_ideas = models.IntegerField(default=0, validators=[MinValueValidator(0)], help_text="Content ideas generated this month")
|
||||
usage_content_words = models.IntegerField(default=0, validators=[MinValueValidator(0)], help_text="Content words generated this month")
|
||||
usage_images_basic = models.IntegerField(default=0, validators=[MinValueValidator(0)], help_text="Basic AI images this month")
|
||||
usage_images_premium = models.IntegerField(default=0, validators=[MinValueValidator(0)], help_text="Premium AI images this month")
|
||||
usage_image_prompts = models.IntegerField(default=0, validators=[MinValueValidator(0)], help_text="Image prompts this month")
|
||||
usage_ahrefs_queries = models.IntegerField(default=0, validators=[MinValueValidator(0)], help_text="Ahrefs queries used this month")
|
||||
usage_period_start = models.DateTimeField(null=True, blank=True, help_text="Current billing period start")
|
||||
usage_period_end = models.DateTimeField(null=True, blank=True, help_text="Current billing period end")
|
||||
|
||||
@@ -216,37 +212,12 @@ class Plan(models.Model):
|
||||
validators=[MinValueValidator(1)],
|
||||
help_text="Maximum total keywords allowed (hard limit)"
|
||||
)
|
||||
max_clusters = models.IntegerField(
|
||||
default=100,
|
||||
validators=[MinValueValidator(1)],
|
||||
help_text="Maximum AI keyword clusters allowed (hard limit)"
|
||||
)
|
||||
|
||||
# Monthly Limits (Reset on billing cycle)
|
||||
max_content_ideas = models.IntegerField(
|
||||
default=300,
|
||||
validators=[MinValueValidator(1)],
|
||||
help_text="Maximum AI content ideas per month"
|
||||
)
|
||||
max_content_words = models.IntegerField(
|
||||
default=100000,
|
||||
validators=[MinValueValidator(1)],
|
||||
help_text="Maximum content words per month (e.g., 100000 = 100K words)"
|
||||
)
|
||||
max_images_basic = models.IntegerField(
|
||||
default=300,
|
||||
max_ahrefs_queries = models.IntegerField(
|
||||
default=0,
|
||||
validators=[MinValueValidator(0)],
|
||||
help_text="Maximum basic AI images per month"
|
||||
)
|
||||
max_images_premium = models.IntegerField(
|
||||
default=60,
|
||||
validators=[MinValueValidator(0)],
|
||||
help_text="Maximum premium AI images per month (DALL-E)"
|
||||
)
|
||||
max_image_prompts = models.IntegerField(
|
||||
default=300,
|
||||
validators=[MinValueValidator(0)],
|
||||
help_text="Maximum image prompts per month"
|
||||
help_text="Monthly Ahrefs keyword research queries (0 = disabled)"
|
||||
)
|
||||
|
||||
# Billing & Credits (Phase 0: Credit-only system)
|
||||
|
||||
@@ -13,9 +13,7 @@ class PlanSerializer(serializers.ModelSerializer):
|
||||
'id', 'name', 'slug', 'price', 'original_price', 'billing_cycle', 'annual_discount_percent',
|
||||
'is_featured', 'features', 'is_active',
|
||||
'max_users', 'max_sites', 'max_industries', 'max_author_profiles',
|
||||
'max_keywords', 'max_clusters',
|
||||
'max_content_ideas', 'max_content_words',
|
||||
'max_images_basic', 'max_images_premium', 'max_image_prompts',
|
||||
'max_keywords', 'max_ahrefs_queries',
|
||||
'included_credits', 'extra_credit_price', 'allow_credit_topup',
|
||||
'auto_credit_topup_threshold', 'auto_credit_topup_amount',
|
||||
'stripe_product_id', 'stripe_price_id', 'credits_per_month'
|
||||
|
||||
Reference in New Issue
Block a user