cleanup: trim bloated multi-line comments across the project

This commit is contained in:
2026-08-26 03:22:20 +03:30
parent 83435c5a5f
commit 683bd40169
27 changed files with 235 additions and 699 deletions

View File

@@ -14,31 +14,21 @@ class Plan(models.Model):
price = models.PositiveIntegerField()
currency = models.CharField(max_length=10, default='IRT')
discount_percent = models.PositiveSmallIntegerField(default=0)
popular = models.BooleanField(default=False) # <-- اصلاح/افزوده شده
# ⚠️ اصلاح دیگه: سند طراحی هیچ فیلد duration‌ای برای Plan نداره، در
# نتیجه‌ی این نبود، activate_subscription قبلاً مدت اشتراک رو با یک
# قاعده‌ی stub (چک کردن کلمه‌ی «سالانه»/yearly در عنوان) حدس می‌زد که
# شکننده و وابسته به متن title بود. duration_days اینجا به‌عنوان منبع
# صریح و قابل‌اتکای مدت اشتراک اضافه شده؛ پیش‌فرض ۳۰ روز.
duration_days = models.PositiveIntegerField(default=30) # <-- اصلاح/افزوده شده
popular = models.BooleanField(default=False)
# منبعِ صریحِ مدتِ اشتراک؛ بدونش activate_subscription مجبور بود مدت رو
# از رویِ متنِ title (مثلاً کلمه‌ی «سالانه») حدس بزنه.
duration_days = models.PositiveIntegerField(default=30)
def __str__(self):
return self.title
class Subscription(models.Model):
"""
⚠️ اصلاح نسبت به سند اولیه: STATUS_CHOICES در سند فقط شامل
active/expired/canceled بود. اما در جریان POST /api/subscription/purchase
یک Subscription قبل از تایید پرداخت (که با payment webhook میاد) ساخته
می‌شه؛ بدون یک وضعیت میانی، راهی برای نمایش «سفارش ثبت شده ولی هنوز
پرداخت تایید نشده» وجود نداره. برای همین وضعیت pending اضافه و به‌عنوان
پیش‌فرض ساخت (به‌جای active در سند) تنظیم شده؛ فعال‌سازی واقعی توسط
subscription.services.activate_subscription بعد از webhook پرداخت انجام
می‌شه.
"""
"""وضعیتِ pending برای فاصله‌ی بینِ ساختنِ Subscription (در purchase) و
تاییدِ پرداخت (webhook)؛ فعال‌سازیِ واقعی توسطِ
subscription.services.activate_subscription انجام می‌شه."""
STATUS_CHOICES = [
('pending', 'در انتظار پرداخت'), # <-- اصلاح/افزوده شده
('pending', 'در انتظار پرداخت'),
('active', 'فعال'),
('expired', 'منقضی'),
('canceled', 'لغوشده'),
@@ -50,19 +40,11 @@ class Subscription(models.Model):
started_at = models.DateTimeField(auto_now_add=True)
expires_at = models.DateTimeField(null=True, blank=True)
order_id = models.IntegerField(null=True, blank=True) # ارجاع سبک به payment.Order
# 🔒 اصلاحِ رگرسیونِ concurrency در PurchaseView.post: چون Subscription
# فقط یک ردیف در ازای هر user_id داره، دو درخواستِ هم‌زمانِ خریدِ همون
# کاربر (مثلاً با همون plan) می‌تونن دقیقاً به یک وضعیتِ میانیِ یکسان
# برسن (status='pending', همون plan_id, order_id=None) — یعنی مقایسه‌ی
# مقادیرِ فیلدها (که قبلاً به‌عنوانِ CAS guard در cleanup استفاده می‌شد)
# نمی‌تونه بینِ «ردیفِ نوشته‌شده توسطِ خودِ همین درخواست» و «ردیفِ
# نوشته‌شده توسطِ یک درخواستِ هم‌زمانِ دیگه» تمایز بذاره. version یک
# شمارنده‌ی صریحه که PurchaseView.post هر بار که واقعاً روی این ردیف
# می‌نویسه (با UPDATE اتمیکِ version=F('version')+1، بدونِ نیاز به
# select_for_update/نگه‌داشتنِ قفل) افزایشش می‌ده؛ پس حتی وقتی محتوای
# semantic فیلدهای دیگه بینِ دو نویسنده‌ی هم‌زمان یکسانه، version همیشه
# بینِ نوشته‌های مجزا فرق می‌کنه و می‌تونه به‌عنوانِ CAS token قابل‌اتکا
# برای cleanup استفاده بشه.
# چون Subscription فقط یک ردیف در ازای هر user_id داره، دو خریدِ هم‌زمانِ
# همون کاربر می‌تونن به وضعیتِ میانیِ کاملاً یکسانی برسن (مقایسه‌ی
# فیلدها کافی نیست برای CAS). version با UPDATEِ اتمیکِ
# version=F('version')+1 (بدونِ select_for_update) هر نوشتنِ واقعی رو
# از نوشتنِ هم‌زمانِ دیگری تمیز می‌ده.
version = models.PositiveIntegerField(default=0)
def __str__(self):