@@ -0,0 +1,23 @@ +# Generated by Django 5.0.11 on 2025-12-25 16:46 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('payments', '0019_move_points_to_features'), + ] + + operations = [ + migrations.AlterField( + model_name='paymentplanfeature', + name='measurement_unit', + field=models.CharField(choices=[('text_page', 'Text Page'), ('file', 'File (pcs)'), ('time', 'Time (mins)')], default='text_page', max_length=15, verbose_name='Measurement unit'), + ), + migrations.AlterField( + model_name='paymentplanfeature', + name='quantity', + field=models.PositiveIntegerField(default=1, verbose_name='Quantity'), + ), + ] @@ -0,0 +1,101 @@ +# Generated by Django 5.0.11 on 2025-12-25 15:32 + +import math +from django.db import migrations +from decimal import Decimal + + +def update_plans_features_quantity(apps, schema_editor): + PaymentPlan = apps.get_model('payments', 'PaymentPlan') + PaymentPlanFeature = apps.get_model('payments', 'PaymentPlanFeature') + NeuronModel = apps.get_model('ml_model', 'NeuronModel') + + model_configs = { + 'sora': (Decimal('1080'), 'file'), + 'kling': (Decimal('270'), 'file'), + 'runway': (Decimal('150'), 'file'), + 'speedance': (Decimal('216'), 'file'), + 'veo': (Decimal('640'), 'file'), + 'hailuo': (Decimal('147'), 'file'), + 'minimaxvideo': (Decimal('150'), 'file'), + 'ray': (Decimal('135'), 'file'), + 'hunyuan': (Decimal('370'), 'file'), + 'lyria': (Decimal('36'), 'time'), + 'suno': (Decimal('17.5'), 'time'), + 'minimaxmusic': (Decimal('10.5'), 'time'), + 'stablemusic': (Decimal('80') / (Decimal('3') + Decimal('10') / Decimal('60')), 'time'), + 'chatgpt': (Decimal('3.28'), 'text_page'), + 'chatgpt_5': (Decimal('0.9'), 'text_page'), + 'claude': (Decimal('5.4'), 'text_page'), + 'gemini': (Decimal('7.92'), 'text_page'), + 'grok': (Decimal('5.76'), 'text_page'), + 'perplexity': (Decimal('8.6'), 'text_page'), + 'qwen': (Decimal('0.076'), 'text_page'), + 'qwen_235B': (Decimal('0.23'), 'text_page'), + 'mistral': (Decimal('0.07'), 'text_page'), + 'deepseek': (Decimal('2.8'), 'text_page'), + 'llama': (Decimal('0.23'), 'text_page'), + 'dalle': (Decimal('2'), 'file'), + 'midjourney': (Decimal('2'), 'file'), + 'stablediffusion': (Decimal('32.5'), 'file'), + 'flux': (Decimal('3'), 'file'), + 'flux_2': (Decimal('72'), 'file'), + 'fluxproultra': (Decimal('18'), 'file'), + 'flux-krea': (Decimal('7.5'), 'file'), + 'ideogram': (Decimal('9'), 'file'), + 'leonardo': (Decimal('0.0015'), 'file'), + 'seedream': (Decimal('9'), 'file'), + 'reve': (Decimal('7.5'), 'file'), + 'recraft': (Decimal('24'), 'file'), + 'geminiimage': (Decimal('19.5'), 'file'), + 'nanobanana': (Decimal('90'), 'file'), + 'wan': (Decimal('50'), 'file'), + 'gptimage': (Decimal('125'), 'file'), + } + + plans = PaymentPlan.objects.prefetch_related('accessed_models').all() + models = NeuronModel.objects.select_related('category').all() + + features_to_create = [] + + for plan in plans: + order_counter = 1 + accessed_model_ids = set(plan.accessed_models.values_list('pk', flat=True)) + + for model in models: + if model.pk not in accessed_model_ids: + continue + + model_config = model_configs.get(model.slug) + + if model_config is None: + continue + + max_price, measurement_unit = model_config + quantity = math.floor(plan.tokens_per_plan / max_price) + + feature = PaymentPlanFeature( + plan=plan, + name=model.title or model.slug, + quantity=quantity, + category=model.category, + measurement_unit=measurement_unit, + order=order_counter + ) + features_to_create.append(feature) + order_counter += 1 + + PaymentPlanFeature.objects.all().delete() + PaymentPlanFeature.objects.bulk_create(features_to_create) + + +class Migration(migrations.Migration): + + dependencies = [ + ('payments', '0020_alter_paymentplanfeature_measurement_unit_and_more'), + ] + + operations = [ + migrations.RunPython(update_plans_features_quantity, migrations.RunPython.noop) + ] + @@ -16,7 +16,7 @@ class PaymentPlanFeature(OrderedModel): PaymentPlan, on_delete=models.CASCADE, related_name='features', verbose_name=_('Payment Plan') ) name = models.CharField(max_length=30, verbose_name=_('Name')) - quantity = models.PositiveSmallIntegerField(default=1, verbose_name=_('Quantity')) + quantity = models.PositiveIntegerField(default=1, verbose_name=_('Quantity')) category = models.ForeignKey( ModelCategory, on_delete=models.CASCADE,