Initial commit

This commit is contained in:
2026-08-11 16:43:12 +03:30
commit e1d830f6a9
127 changed files with 4454 additions and 0 deletions

55
subscription/models.py Normal file
View File

@@ -0,0 +1,55 @@
from django.db import models
class Plan(models.Model):
"""
⚠️ اصلاح نسبت به سند اولیه: نمونه‌ی پاسخ GET /api/subscription/plans در
سند Endpointهای API یک فیلد boolean به اسم `popular` داره («ماهانه» →
false، «سالانه» → true) که در دیاگرام مدل‌ها (سند معماری داده) برای
Plan اصلاً ذکر نشده. چون بدون این فیلد نمی‌شه دقیقاً همون response
schema رو پیاده‌سازی کرد، اینجا اضافه شده — دقیقاً مثل فیکس is_correct
روی content.Choice در فاز ۱.
"""
title = models.CharField(max_length=50)
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) # <-- اصلاح/افزوده شده
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 پرداخت انجام
می‌شه.
"""
STATUS_CHOICES = [
('pending', 'در انتظار پرداخت'), # <-- اصلاح/افزوده شده
('active', 'فعال'),
('expired', 'منقضی'),
('canceled', 'لغوشده'),
]
user_id = models.IntegerField(unique=True, db_index=True) # ارجاع سبک به accounts.User
plan = models.ForeignKey(Plan, on_delete=models.SET_NULL, null=True, related_name='subscriptions')
status = models.CharField(max_length=15, choices=STATUS_CHOICES, default='pending')
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
def __str__(self):
return f"sub-user{self.user_id}-{self.status}"