Files
MathApp/ai_tutor/tests_quota.py
Zareian 9c3adc3e60 Subscriptions only: Bazaar panel prices (598/898/1398k), assistant quota 5/3/3 from a cost calculation, packs off sale
- subscription.0016: prices equal to the Bazaar panel (senior), ai_daily_quota 5/3/3, card features; packs on_sale=False
  (one paid pack order, user 26, keeps its credits; pack paths stay for that order and for admin).
- Quota math in docs/ai-cost-and-guardrails.md: ~77% of a Bazaar sale reaches us; worst case (full quota every day)
  the assistant costs 23/27/35% of it.
- Assistant quota message points to the subscription, not packs.
982 tests green.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-12 19:57:16 +03:30

54 lines
2.7 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
"""
سقفِ روزانه‌ی دستیار: رایگان در برابرِ اشتراکی (۲۰۲۶-۱۰-۰۱). تا آن روز همه ۱۵ سوال
داشتند، یعنی گران‌ترین بخشِ اپ برای کاربرِ بی‌اشتراک هم کامل باز بود.
"""
from datetime import timedelta
from django.core.cache import cache
from django.test import TestCase, override_settings
from django.utils import timezone
from rest_framework.test import APIClient
from accounts.authentication import issue_access_token
from accounts.models import User
from subscription.models import Plan, Subscription
from subscription.services import ai_daily_quota
@override_settings(AI_DAILY_QUOTA_FREE=2)
class DailyQuotaTests(TestCase):
def setUp(self):
cache.clear()
self.user = User.objects.create(phone='09120006001')
self.client = APIClient()
self.client.credentials(HTTP_AUTHORIZATION=f'Bearer {issue_access_token(self.user.id)}')
def ask(self):
return self.client.post('/api/ai/ask', {'userQuestion': '۲ + ۲ چند میشه؟'}, format='json')
def test_free_user_gets_the_free_quota_and_a_hint_to_subscribe(self):
self.assertEqual([self.ask().status_code for _ in range(2)], [200, 200])
blocked = self.ask()
self.assertEqual(blocked.status_code, 429)
self.assertIn('اشتراک', blocked.json()['detail']) # بسته از subscription.0016 فروخته نمی‌شود
def test_remaining_quota_follows_the_users_own_limit(self):
self.assertEqual(self.ask().json()['remainingQuota'], 1)
def test_subscriber_gets_the_plans_quota(self):
plan = Plan.objects.create(title='ماهانه', price=99000, duration_days=30, ai_daily_quota=4)
Subscription.objects.create(user_id=self.user.id, plan=plan, status='active',
expires_at=timezone.now() + timedelta(days=30))
self.assertEqual(ai_daily_quota(self.user.id), 4)
self.assertEqual([self.ask().status_code for _ in range(5)], [200, 200, 200, 200, 429])
def test_expired_subscription_falls_back_to_free(self):
plan = Plan.objects.create(title='ماهانه', price=99000, duration_days=30, ai_daily_quota=40)
Subscription.objects.create(user_id=self.user.id, plan=plan, status='active',
expires_at=timezone.now() - timedelta(days=1))
self.assertEqual(ai_daily_quota(self.user.id), 2)
def test_gifted_subscription_without_plan_gets_the_default(self):
Subscription.objects.create(user_id=self.user.id, plan=None, status='active', expires_at=None)
self.assertEqual(ai_daily_quota(self.user.id), 15)