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>
This commit is contained in:
2026-10-12 20:33:38 +03:30
parent 9c3adc3e60
commit 947f946909
39 changed files with 398 additions and 1174 deletions

View File

@@ -0,0 +1,28 @@
"""
بسته‌ی سوال از ریشه حذف می‌شود (تصمیمِ سینیور و مالک، ۲۰۲۶-۱۰-۱۲). پیش از حذفِ ستون‌ها و جدول‌ها (0018):
- ردیف‌های پلنِ بسته پاک می‌شوند. سفارش‌هایشان می‌مانند (ارجاعِ سبکِ plan_id؛ فاکتور از plan_title می‌خواند).
تنها سفارشِ پرداخت‌شده‌ی بسته روی سرور مالِ حسابِ آزمایشیِ صاحبِ شرکت بود (کاربرِ ۲۶).
- اگر اشتراکی به پلنِ بسته وصل باشد migration می‌شکند؛ نباید باشد (بسته هرگز Subscription نمی‌ساخت).
- سقفِ دستیارِ همه‌ی اشتراک‌های فروشی ۴ سوال در روز (مالک). حساب: docs/ai-cost-and-guardrails.md «اشتراک‌ها».
"""
from django.core.cache import cache
from django.db import migrations
def forward(apps, schema_editor):
Plan = apps.get_model('subscription', 'Plan')
Subscription = apps.get_model('subscription', 'Subscription')
packs = Plan.objects.filter(kind='pack')
attached = Subscription.objects.filter(plan__in=packs).count()
if attached:
raise RuntimeError(f'{attached} اشتراک به پلنِ بسته وصل است؛ دستی بررسی کنید.')
packs.delete()
Plan.objects.filter(on_sale=True).update(ai_daily_quota=4)
for key in ('subscription:plans:v3', 'subscription:plans:v4'):
cache.delete(key)
class Migration(migrations.Migration):
dependencies = [('subscription', '0016_subscriptions_only_2026_10')]
operations = [migrations.RunPython(forward, migrations.RunPython.noop)]

View File

@@ -0,0 +1,31 @@
# Generated by Django 5.2.17 on 2026-10-12 16:48
from django.db import migrations
class Migration(migrations.Migration):
dependencies = [
('subscription', '0017_no_question_packs'),
]
operations = [
migrations.DeleteModel(
name='HeartsPass',
),
migrations.DeleteModel(
name='QuestionCredit',
),
migrations.RemoveField(
model_name='plan',
name='hearts_days',
),
migrations.RemoveField(
model_name='plan',
name='kind',
),
migrations.RemoveField(
model_name='plan',
name='question_credits',
),
]