Files
MathApp/subscription/tests_security_review.py
Zareian 947f946909 Question packs removed at the root; all subscriptions 4 assistant questions a day; Bazaar is subscription-only
- subscription.0017/0018, payment.0013: pack plans deleted, QuestionCredit/HeartsPass models and Plan.kind /
  question_credits / hearts_days / Order.question_credits / hearts_days dropped. The only paid pack order was the
  company owner's test account (user 26).
- Assistant: no credit spending; quota is the daily cap only (free 2, every plan 4, gift subscription 4).
- Bazaar: verify_purchase is subscription-only (no inapp guess), start/purchase responses lose productType,
  verify refuses an order without a subscription. A paid order with no subscription now logs ERROR.
- Removed POST /api/payment/orders (internal; no caller). Its permission tests stay.
- Pack-based tests rewritten on subscriptions (refund, security, Bazaar token); pack-only test files deleted.
- docs: profit table for 4/day on both payment routes plus free users; handbook, operations, CLAUDE.md current.
949 tests green.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-12 20:33:38 +03:30

59 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 django.utils import timezone
from .models import Plan, Subscription
class PaidOrderWithDeletedPlanTests(TestCase):
"""پرداختِ سفارشی که پلنش بعد از ساخت پاک شده: مدتِ ثبت‌شده روی سفارش داده می‌شود و ERROR لاگ می‌شود."""
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)}')
plan = Plan.objects.get(on_sale=True, duration_days=90)
order = Order.objects.get(pk=app.post('/api/subscription/purchase', {'planId': str(plan.id)},
format='json').json()['orderId'])
plan.delete()
with self.assertLogs('subscription.services', level='ERROR'):
apply_order_payment_result(order=order, gateway='zarinpal', gateway_ref_id='GONE-1', new_status='paid', event='t')
sub = Subscription.objects.get(user_id=user.id)
self.assertAlmostEqual((sub.expires_at - timezone.now()).days, 89, delta=1)
def test_paid_order_without_a_subscription_is_logged_as_error(self):
order = Order.objects.create(user_id=1, amount=1000, plan_id=999999, idempotency_key='sec-noplan')
with self.assertLogs('payment.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(on_sale=True, duration_days=90)
data = {f: getattr(pack, f) for f in ('title', 'price', 'discount_percent', 'duration_days', 'badge',
'ai_daily_quota', '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)