multi sector clustering erroro rasing, adn tasks page word coutn monthly limits removal

This commit is contained in:
IGNY8 VPS (Salman)
2026-01-19 08:20:43 +00:00
parent e57c4bf1ac
commit 29ce8139d9
8 changed files with 155 additions and 86 deletions

View File

@@ -1032,7 +1032,7 @@ from rest_framework.decorators import api_view, permission_classes
def get_usage_summary(request):
"""
Get comprehensive usage summary for current account.
Includes hard limits (sites, users, keywords, clusters) and monthly limits (ideas, words, images).
Includes hard limits (sites, users, keywords) and monthly limits (ahrefs queries only).
GET /api/v1/billing/usage-summary/
"""

View File

@@ -257,12 +257,11 @@ class BillingConfiguration(models.Model):
class PlanLimitUsage(AccountBaseModel):
"""
Track monthly usage of plan limits (ideas, words, images, prompts)
Track monthly usage of plan limits (ideas, images, prompts)
Resets at start of each billing period
"""
LIMIT_TYPE_CHOICES = [
('content_ideas', 'Content Ideas'),
('content_words', 'Content Words'),
('images_basic', 'Basic Images'),
('images_premium', 'Premium Images'),
('image_prompts', 'Image Prompts'),

View File

@@ -358,31 +358,8 @@ class Content(SoftDeletableModel, SiteSectorBaseModel):
super().save(*args, **kwargs)
# Increment usage for new content or if word count increased
if self.content_html and self.word_count:
# Only count newly generated words
new_words = self.word_count - old_word_count if not is_new else self.word_count
if new_words > 0:
from igny8_core.business.billing.services.limit_service import LimitService
try:
# Get account from site
account = self.site.account if self.site else None
if account:
LimitService.increment_usage(
account=account,
limit_type='content_words',
amount=new_words,
metadata={
'content_id': self.id,
'content_title': self.title,
'site_id': self.site.id if self.site else None,
}
)
except Exception as e:
import logging
logger = logging.getLogger(__name__)
logger.error(f"Error incrementing word usage for content {self.id}: {str(e)}")
# NOTE: Content words no longer tracked as a monthly plan limit.
# Credits are the only enforcement for content generation.
def soft_delete(self, user=None, reason=None, retention_days=None):
"""

View File

@@ -30,20 +30,12 @@ class ContentGenerationService:
Raises:
InsufficientCreditsError: If account doesn't have enough credits
"""
from igny8_core.business.billing.services.limit_service import LimitService, MonthlyLimitExceededError
# Get tasks
tasks = Tasks.objects.filter(id__in=task_ids, account=account)
# Calculate estimated credits needed based on word count
total_word_count = sum(task.word_count or 1000 for task in tasks)
# Check monthly word count limit
try:
LimitService.check_monthly_limit(account, 'content_words', amount=total_word_count)
except MonthlyLimitExceededError as e:
raise InsufficientCreditsError(str(e))
# Check credits
try:
self.credit_service.check_credits(account, 'content_generation', total_word_count)

View File

@@ -292,7 +292,6 @@ class TasksViewSet(SiteSectorModelViewSet):
content_type_filter = request.query_params.get('content_type', '')
content_structure_filter = request.query_params.get('content_structure', '')
cluster_filter = request.query_params.get('cluster', '')
source_filter = request.query_params.get('source', '')
search = request.query_params.get('search', '')
# Apply search to base queryset
@@ -310,8 +309,6 @@ class TasksViewSet(SiteSectorModelViewSet):
status_qs = status_qs.filter(content_structure=content_structure_filter)
if cluster_filter:
status_qs = status_qs.filter(cluster_id=cluster_filter)
if source_filter:
status_qs = status_qs.filter(source=source_filter)
statuses = list(set(status_qs.values_list('status', flat=True)))
statuses = sorted([s for s in statuses if s])
status_labels = {
@@ -333,8 +330,6 @@ class TasksViewSet(SiteSectorModelViewSet):
type_qs = type_qs.filter(content_structure=content_structure_filter)
if cluster_filter:
type_qs = type_qs.filter(cluster_id=cluster_filter)
if source_filter:
type_qs = type_qs.filter(source=source_filter)
content_types = list(set(type_qs.values_list('content_type', flat=True)))
content_types = sorted([t for t in content_types if t])
type_labels = {
@@ -356,8 +351,6 @@ class TasksViewSet(SiteSectorModelViewSet):
structure_qs = structure_qs.filter(content_type=content_type_filter)
if cluster_filter:
structure_qs = structure_qs.filter(cluster_id=cluster_filter)
if source_filter:
structure_qs = structure_qs.filter(source=source_filter)
structures = list(set(structure_qs.values_list('content_structure', flat=True)))
structures = sorted([s for s in structures if s])
structure_labels = {
@@ -381,8 +374,6 @@ class TasksViewSet(SiteSectorModelViewSet):
cluster_qs = cluster_qs.filter(content_type=content_type_filter)
if content_structure_filter:
cluster_qs = cluster_qs.filter(content_structure=content_structure_filter)
if source_filter:
cluster_qs = cluster_qs.filter(source=source_filter)
from igny8_core.modules.planner.models import Clusters
cluster_ids = list(set(
cluster_qs.exclude(cluster_id__isnull=True)
@@ -394,35 +385,12 @@ class TasksViewSet(SiteSectorModelViewSet):
for c in clusters
]
# Get sources (filtered by other fields)
source_qs = base_qs
if status_filter:
source_qs = source_qs.filter(status=status_filter)
if content_type_filter:
source_qs = source_qs.filter(content_type=content_type_filter)
if content_structure_filter:
source_qs = source_qs.filter(content_structure=content_structure_filter)
if cluster_filter:
source_qs = source_qs.filter(cluster_id=cluster_filter)
sources = list(set(source_qs.values_list('source', flat=True)))
sources = sorted([s for s in sources if s])
source_labels = {
'manual': 'Manual',
'planner': 'Planner',
'ai': 'AI',
}
source_options = [
{'value': s, 'label': source_labels.get(s, s.title())}
for s in sources
]
return success_response(
data={
'statuses': status_options,
'content_types': content_type_options,
'content_structures': content_structure_options,
'clusters': cluster_options,
'sources': source_options,
},
request=request
)
@@ -970,16 +938,6 @@ class ContentViewSet(SiteSectorModelViewSet):
word_count = calculate_word_count(html_content)
serializer.validated_data['word_count'] = word_count
# Check monthly word count limit (enforces ALL entry points: manual, import, AI, automation)
if account and word_count > 0:
from igny8_core.business.billing.services.limit_service import LimitService, MonthlyLimitExceededError
from rest_framework.exceptions import ValidationError
try:
LimitService.check_monthly_limit(account, 'content_words', amount=word_count)
except MonthlyLimitExceededError as e:
raise ValidationError(str(e))
if account:
serializer.save(account=account)
else:

View File

@@ -22,11 +22,7 @@ def reset_monthly_plan_limits():
It finds all accounts where the billing period has ended and resets their monthly usage.
Monthly limits that get reset:
- content_ideas
- content_words
- images_basic
- images_premium
- image_prompts
- ahrefs_queries
Hard limits (sites, users, keywords, clusters) are NOT reset.
"""