- 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>
39 lines
1.6 KiB
Python
39 lines
1.6 KiB
Python
from rest_framework import serializers
|
|
|
|
|
|
class PlanSerializer(serializers.Serializer):
|
|
id = serializers.CharField()
|
|
title = serializers.CharField()
|
|
price = serializers.IntegerField()
|
|
currency = serializers.CharField(required=False)
|
|
popular = serializers.BooleanField()
|
|
discountPercent = serializers.IntegerField(required=False)
|
|
durationDays = serializers.IntegerField(required=False)
|
|
features = serializers.ListField(child=serializers.CharField())
|
|
badge = serializers.CharField(allow_blank=True)
|
|
aiDailyQuota = serializers.IntegerField(help_text='سوال در روز از دستیار برای مشترکِ این پلن.')
|
|
|
|
|
|
class PlansListResponseSerializer(serializers.Serializer):
|
|
plans = PlanSerializer(many=True)
|
|
# تا کارتِ پلن بتواند بگوید «۵ سوال در روز (رایگان: ۳)» بیآنکه عدد در فرانت هاردکد شود.
|
|
freeAiDailyQuota = serializers.IntegerField()
|
|
|
|
|
|
class PurchaseRequestSerializer(serializers.Serializer):
|
|
# هدر Idempotency-Key هم روی همین درخواست لازمه (بخش ۴.۳ سند API)؛
|
|
# از request.headers خونده میشه، نه از بدنه.
|
|
planId = serializers.CharField()
|
|
paymentMethod = serializers.CharField(required=False, default='zarinpal')
|
|
|
|
|
|
class PurchaseResponseSerializer(serializers.Serializer):
|
|
orderId = serializers.CharField()
|
|
paymentUrl = serializers.CharField()
|
|
|
|
|
|
class SubscriptionStatusResponseSerializer(serializers.Serializer):
|
|
active = serializers.BooleanField()
|
|
planId = serializers.CharField(allow_null=True)
|
|
expiresAt = serializers.DateTimeField(allow_null=True)
|