let the subscription card come from the server
کارتِ اشتراک زیرِ هر پلن فهرستِ امکانات و یک برچسب («محبوبترین»، «بهترین ارزش») نشان میدهد، و هر دو در کدِ فرانت هاردکد بودند — یعنی عوض کردنِ یک بندِ متنی به دیپلویِ تازهی اپ نیاز داشت. Plan حالا features و badge دارد. `popular` سرِ جایش ماند: بولین است و متنِ برچسب را نمیدهد، پس این جایگزینش نیست، کنارش است. هیچکدام اجباری نیستند و پلنهای موجود بدونشان همچنان سرو میشوند. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
23
subscription/migrations/0004_plan_badge_plan_features.py
Normal file
23
subscription/migrations/0004_plan_badge_plan_features.py
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
# Generated by Django 5.2.17 on 2026-09-13 22:30
|
||||||
|
|
||||||
|
from django.db import migrations, models
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('subscription', '0003_subscription_version'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.AddField(
|
||||||
|
model_name='plan',
|
||||||
|
name='badge',
|
||||||
|
field=models.CharField(blank=True, max_length=30),
|
||||||
|
),
|
||||||
|
migrations.AddField(
|
||||||
|
model_name='plan',
|
||||||
|
name='features',
|
||||||
|
field=models.JSONField(blank=True, default=list),
|
||||||
|
),
|
||||||
|
]
|
||||||
@@ -19,6 +19,14 @@ class Plan(models.Model):
|
|||||||
# از رویِ متنِ title (مثلاً کلمهی «سالانه») حدس بزنه.
|
# از رویِ متنِ title (مثلاً کلمهی «سالانه») حدس بزنه.
|
||||||
duration_days = models.PositiveIntegerField(default=30)
|
duration_days = models.PositiveIntegerField(default=30)
|
||||||
|
|
||||||
|
# کارتِ اشتراک زیرِ هر پلن فهرستِ امکانات نشان میدهد («درسهای نامحدود»،
|
||||||
|
# «دستیار هوشمند»…). تا امروز این فهرست در کدِ فرانت هاردکد بود، یعنی
|
||||||
|
# عوض کردنِ یک بند به دیپلویِ تازهی اپ نیاز داشت.
|
||||||
|
features = models.JSONField(default=list, blank=True)
|
||||||
|
# برچسبِ بالای کارت: «محبوبترین»، «بهترین ارزش». `popular` فقط بولین است
|
||||||
|
# و یک متن نمیدهد؛ این جایگزینش نیست، کنارش است.
|
||||||
|
badge = models.CharField(max_length=30, blank=True)
|
||||||
|
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
return self.title
|
return self.title
|
||||||
|
|
||||||
|
|||||||
@@ -9,6 +9,8 @@ class PlanSerializer(serializers.Serializer):
|
|||||||
popular = serializers.BooleanField()
|
popular = serializers.BooleanField()
|
||||||
discountPercent = serializers.IntegerField(required=False)
|
discountPercent = serializers.IntegerField(required=False)
|
||||||
durationDays = serializers.IntegerField(required=False)
|
durationDays = serializers.IntegerField(required=False)
|
||||||
|
features = serializers.ListField(child=serializers.CharField())
|
||||||
|
badge = serializers.CharField(allow_blank=True)
|
||||||
|
|
||||||
|
|
||||||
class PlansListResponseSerializer(serializers.Serializer):
|
class PlansListResponseSerializer(serializers.Serializer):
|
||||||
|
|||||||
@@ -516,3 +516,28 @@ class PurchaseGuestThrottleBypassTests(TestCase):
|
|||||||
|
|
||||||
self.assertFalse(Subscription.objects.filter(user_id=guest2.id).exists())
|
self.assertFalse(Subscription.objects.filter(user_id=guest2.id).exists())
|
||||||
self.assertEqual(Order.objects.filter(user_id=guest2.id).count(), 0)
|
self.assertEqual(Order.objects.filter(user_id=guest2.id).count(), 0)
|
||||||
|
|
||||||
|
|
||||||
|
class PlanCardContractTests(TestCase):
|
||||||
|
"""
|
||||||
|
کارتِ اشتراک در فرانت فهرستِ امکانات و یک برچسب نشان میدهد؛ تا امروز هر
|
||||||
|
دو در کدِ اپ هاردکد بودند، یعنی عوض کردنِ یک بند به دیپلویِ تازه نیاز داشت.
|
||||||
|
"""
|
||||||
|
|
||||||
|
def setUp(self):
|
||||||
|
from django.core.cache import cache
|
||||||
|
cache.clear()
|
||||||
|
|
||||||
|
def test_plans_carry_their_feature_list_and_badge(self):
|
||||||
|
Plan.objects.create(title='طلایی', price=49000, popular=True,
|
||||||
|
badge='محبوبترین',
|
||||||
|
features=['درسهای نامحدود', 'بدون تبلیغ'])
|
||||||
|
row = self.client.get('/api/subscription/plans').json()['plans'][0]
|
||||||
|
self.assertEqual(row['badge'], 'محبوبترین')
|
||||||
|
self.assertEqual(row['features'], ['درسهای نامحدود', 'بدون تبلیغ'])
|
||||||
|
|
||||||
|
def test_a_plan_without_them_still_serializes(self):
|
||||||
|
Plan.objects.create(title='رایگان', price=0)
|
||||||
|
row = self.client.get('/api/subscription/plans').json()['plans'][0]
|
||||||
|
self.assertEqual(row['features'], [])
|
||||||
|
self.assertEqual(row['badge'], '')
|
||||||
|
|||||||
@@ -61,6 +61,8 @@ class PlansListView(APIView):
|
|||||||
'popular': p.popular,
|
'popular': p.popular,
|
||||||
'discountPercent': p.discount_percent,
|
'discountPercent': p.discount_percent,
|
||||||
'durationDays': p.duration_days,
|
'durationDays': p.duration_days,
|
||||||
|
'features': p.features or [],
|
||||||
|
'badge': p.badge,
|
||||||
}
|
}
|
||||||
for p in Plan.objects.all()
|
for p in Plan.objects.all()
|
||||||
]
|
]
|
||||||
|
|||||||
Reference in New Issue
Block a user