Files
MathApp/subscription/tests_security_review.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

58 lines
3.2 KiB
Python

"""
حفاظ‌های بازبینیِ امنیتیِ پیش از تحویل (بسته‌ها و پلن). هر تست رفتاری را نگه می‌دارد که پیش‌تر غلط بود.
"""
from django.contrib.auth import get_user_model
from django.core.cache import cache
from django.test import TestCase
from rest_framework.test import APIClient
from accounts.authentication import issue_access_token
from accounts.models import User
from payment.models import Order
from payment.services import apply_order_payment_result
from .models import Plan
from .services import credit_balance
class PaidPackWithDeletedPlanTests(TestCase):
"""پرداختِ سفارشی که پلنش بعد از ساخت پاک شده بود «paid» می‌شد بی‌هیچ اعتبار و بی‌هیچ لاگی."""
def test_order_snapshot_is_granted_even_if_plan_is_gone(self):
cache.clear()
user = User.objects.create(phone='09120009902')
app = APIClient()
app.credentials(HTTP_AUTHORIZATION=f'Bearer {issue_access_token(user.id)}')
pack = Plan.objects.get(kind='pack', question_credits=20)
Plan.objects.filter(pk=pack.pk).update(on_sale=True) # بسته‌ها از subscription.0016 فروشی نیستند
order = Order.objects.get(pk=app.post('/api/subscription/purchase', {'planId': str(pack.id)},
format='json').json()['orderId'])
pack.delete()
apply_order_payment_result(order=order, gateway='zarinpal', gateway_ref_id='GONE-1', new_status='paid', event='t')
self.assertEqual(credit_balance(user.id), 20)
def test_nothing_to_grant_is_logged_as_error(self):
order = Order.objects.create(user_id=1, amount=1000, plan_id=999999, idempotency_key='sec-noplan')
with self.assertLogs('subscription.services', level='ERROR'):
apply_order_payment_result(order=order, gateway='zarinpal', gateway_ref_id='GONE-2', new_status='paid',
event='t')
class PlanCurrencyIsTomanOnlyTests(TestCase):
"""اپ هر قیمتی را «تومان» نشان می‌دهد و currencyِ پلن بی‌تغییر به زرین‌پال می‌رود؛ IRR یعنی یک‌دهمِ قیمت."""
def test_admin_refuses_irr(self):
admin = get_user_model().objects.create_superuser('root', 'r@example.com', 'pw-for-tests-only')
self.client.force_login(admin)
pack = Plan.objects.get(kind='pack', question_credits=20)
data = {f: getattr(pack, f) for f in ('title', 'price', 'discount_percent', 'duration_days', 'badge',
'ai_daily_quota', 'kind', 'question_credits', 'hearts_days',
'bazaar_sku')}
data.update(currency='IRR', features='[]', on_sale='on')
page = self.client.post(f'/admin/subscription/plan/{pack.pk}/change/', data)
self.assertEqual(page.status_code, 200) # فرم با خطا برگشت
pack.refresh_from_db()
self.assertEqual(pack.currency, 'IRT')
data['currency'] = 'IRT'
self.assertEqual(self.client.post(f'/admin/subscription/plan/{pack.pk}/change/', data).status_code, 302)