- profile publicId ("User482917", accounts/public_id.py); admin shows and searches it
- plans API reports aiDailyQuota per plan and freeAiDailyQuota; migration 0007 sets the
temporary prices (monthly 99,000 / yearly 990,000 toman, 5 tutor questions a day) unless
an admin already edited the yearly plan
- tutor tone follows the learner's age (18+ gets an adult tone at any grade); notation
still follows the grade's book; answer cache keyed by tone (prompt tutor-v12-age-tone)
- POST /api/user/delete: phone users confirm with a fresh SMS code (same checks as login,
now shared in verify_phone_otp), guests type "حذف"; payment records are kept, demo
accounts refused
- delete_users --skip-paid
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
67 lines
3.4 KiB
Python
67 lines
3.4 KiB
Python
"""
|
||
قیمتِ موقتِ پلنها بر اساسِ هزینهی دستیار (مهرِ ۱۴۰۵).
|
||
|
||
هر سوال از دستیار حدودِ ۶۰۰ تومان هزینهی API دارد (docs/ai-cost-and-guardrails.md).
|
||
اشتراکِ سالانهی ۲۹۹ هزار تومانی (۰۰۰۵) فقط ~۴۰ سوال در ماه را پوشش میداد، در حالی که
|
||
مشترک تا ۴۵۰ سوال در ماه میتوانست بپرسد. این قیمتها را صاحبِ پروژه «موقت و معقول»
|
||
خواست، تا تصمیمِ نهاییِ مدیرعامل:
|
||
|
||
- ماهانه ۹۹٬۰۰۰ تومان، سالانه ۹۹۰٬۰۰۰ تومان (قیمتِ ۱۰ ماه، دو ماه هدیه)، هر دو ۵ سوال در روز.
|
||
- کاربرِ معمولی (یکسومِ سقف، ~۵۰ سوال در ماه) ~۳۰ هزار تومان هزینه دارد: ~۳۶٪ِ درآمدِ خالصِ
|
||
ماهانه پس از سهمِ ۱۵٪یِ بازار، و ~۴۳٪ در سالانه. کاربری که هر روز سقف را پر کند (۱۵۰ سوال،
|
||
~۹۰ هزار تومان) در پلنِ ماهانه از درآمدش بیشتر خرج میکند؛ این سقف با درآمدِ واقعی بازبینی شود.
|
||
|
||
ویژگیها فقط چیزی است که کد واقعاً به مشترک میدهد. درسها، آزمونها و گزارشِ والدین برای همه
|
||
رایگاناند و اینجا نیامدهاند. سقفِ سوال را خودِ اپ از ai_daily_quota میسازد و در features نیست.
|
||
|
||
قاعده: پلنِ سالانه فقط وقتی عوض میشود که هنوز همان قیمتِ پیشفرضِ ۲۹۹ هزار تومانِ ۰۰۰۵ را
|
||
دارد، یعنی کسی در ادمین ویرایشش نکرده. پلنِ ماهانه فقط وقتی ساخته میشود که هیچ پلنِ ۳۰ روزهای
|
||
وجود ندارد.
|
||
"""
|
||
from django.db import migrations
|
||
|
||
YEARLY_TITLE = 'اشتراک یکساله'
|
||
YEARLY = {
|
||
'price': 990_000,
|
||
'discount_percent': 17,
|
||
'popular': True,
|
||
'badge': 'دو ماه هدیه',
|
||
'ai_daily_quota': 5,
|
||
'features': ['قلبِ نامحدود؛ هیچوقت وسطِ تمرین متوقف نمیشی', 'دوازده ماه، به قیمتِ ده ماه'],
|
||
}
|
||
MONTHLY = {
|
||
'title': 'اشتراک ماهانه',
|
||
'price': 99_000,
|
||
'currency': 'IRT',
|
||
'discount_percent': 0,
|
||
'popular': False,
|
||
'duration_days': 30,
|
||
'badge': '',
|
||
'ai_daily_quota': 5,
|
||
'features': ['قلبِ نامحدود؛ هیچوقت وسطِ تمرین متوقف نمیشی', 'هر وقت خواستی تمدید کن'],
|
||
}
|
||
|
||
|
||
def apply_prices(apps, schema_editor):
|
||
Plan = apps.get_model('subscription', 'Plan')
|
||
Plan.objects.filter(title=YEARLY_TITLE, price=299_000).update(**YEARLY)
|
||
if not Plan.objects.filter(duration_days=30).exists():
|
||
Plan.objects.create(**MONTHLY)
|
||
|
||
|
||
def undo(apps, schema_editor):
|
||
Plan = apps.get_model('subscription', 'Plan')
|
||
Plan.objects.filter(title=MONTHLY['title'], subscriptions__isnull=True).delete()
|
||
Plan.objects.filter(title=YEARLY_TITLE, price=YEARLY['price']).update(price=299_000, ai_daily_quota=15)
|
||
|
||
|
||
class Migration(migrations.Migration):
|
||
|
||
dependencies = [
|
||
('subscription', '0006_plan_ai_daily_quota'),
|
||
]
|
||
|
||
operations = [
|
||
migrations.RunPython(apply_prices, undo),
|
||
]
|