adding
This commit is contained in:
@@ -0,0 +1,124 @@
|
||||
# Generated by Django 5.1.15 on 2026-08-23 12:32
|
||||
|
||||
import django.db.models.deletion
|
||||
from django.conf import settings
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
initial = True
|
||||
|
||||
dependencies = [
|
||||
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.CreateModel(
|
||||
name='BazaarSettings',
|
||||
fields=[
|
||||
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||
('access_token', models.CharField(blank=True, max_length=255, verbose_name='Access Token')),
|
||||
('refresh_token', models.CharField(blank=True, max_length=255, verbose_name='Refresh Token')),
|
||||
('package_name', models.CharField(blank=True, max_length=150, verbose_name='application id اپ (مثلا ir.example.app)')),
|
||||
('updated_at', models.DateTimeField(auto_now=True)),
|
||||
],
|
||||
options={
|
||||
'verbose_name': 'تنظیمات کافه\u200cبازار',
|
||||
'verbose_name_plural': 'تنظیمات کافه\u200cبازار',
|
||||
},
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name='FeaturePlan',
|
||||
fields=[
|
||||
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||
('key', models.SlugField(unique=True, verbose_name='کلید ریزاپ')),
|
||||
('name', models.CharField(max_length=150, verbose_name='نام نمایشی')),
|
||||
('is_purchasable', models.BooleanField(default=True, verbose_name='قابل\u200cفروش')),
|
||||
],
|
||||
options={
|
||||
'verbose_name': 'ریزاپ قابل\u200cفعال\u200cسازی',
|
||||
'verbose_name_plural': 'ریزاپ\u200cهای قابل\u200cفعال\u200cسازی',
|
||||
},
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name='GemPack',
|
||||
fields=[
|
||||
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||
('bazaar_sku', models.CharField(max_length=100, unique=True, verbose_name='SKU کافه\u200cبازار')),
|
||||
('display_name', models.CharField(max_length=150, verbose_name='نام نمایشی')),
|
||||
('gem_amount', models.PositiveIntegerField(verbose_name='تعداد جم')),
|
||||
('is_active', models.BooleanField(default=True, verbose_name='قابل\u200cخرید')),
|
||||
('sort_order', models.PositiveIntegerField(default=0)),
|
||||
],
|
||||
options={
|
||||
'verbose_name': 'بسته\u200cی جم',
|
||||
'verbose_name_plural': 'بسته\u200cهای جم',
|
||||
'ordering': ['sort_order', 'gem_amount'],
|
||||
},
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name='BazaarPurchase',
|
||||
fields=[
|
||||
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||
('purchase_token', models.CharField(max_length=255, unique=True, verbose_name='Purchase Token')),
|
||||
('status', models.CharField(choices=[('pending', 'در انتظار تایید'), ('verified', 'تاییدشده'), ('failed', 'ناموفق')], default='pending', max_length=10)),
|
||||
('gems_granted', models.PositiveIntegerField(default=0)),
|
||||
('created_at', models.DateTimeField(auto_now_add=True)),
|
||||
('verified_at', models.DateTimeField(blank=True, null=True)),
|
||||
('user', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='bazaar_purchases', to=settings.AUTH_USER_MODEL)),
|
||||
('gem_pack', models.ForeignKey(on_delete=django.db.models.deletion.PROTECT, related_name='+', to='billing.gempack')),
|
||||
],
|
||||
options={
|
||||
'verbose_name': 'خرید کافه\u200cبازار',
|
||||
'verbose_name_plural': 'خریدهای کافه\u200cبازار',
|
||||
'ordering': ['-created_at'],
|
||||
},
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name='GemTransaction',
|
||||
fields=[
|
||||
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||
('amount', models.IntegerField(verbose_name='مقدار (مثبت/منفی)')),
|
||||
('reason', models.CharField(choices=[('purchase', 'خرید از کافه\u200cبازار'), ('feature_activation', 'فعال\u200cسازی ریزاپ'), ('referral_bonus', 'پاداش معرفی'), ('referral_milestone', 'پاداش دستاورد معرفی'), ('admin_adjustment', 'اصلاح دستی ادمین')], max_length=30)),
|
||||
('note', models.CharField(blank=True, max_length=255)),
|
||||
('created_at', models.DateTimeField(auto_now_add=True)),
|
||||
('user', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='gem_transactions', to=settings.AUTH_USER_MODEL)),
|
||||
],
|
||||
options={
|
||||
'verbose_name': 'تراکنش جم',
|
||||
'verbose_name_plural': 'تراکنش\u200cهای جم',
|
||||
'ordering': ['-created_at'],
|
||||
},
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name='FeatureActivation',
|
||||
fields=[
|
||||
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||
('expires_at', models.DateTimeField(verbose_name='تا تاریخ')),
|
||||
('updated_at', models.DateTimeField(auto_now=True)),
|
||||
('user', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='feature_activations', to=settings.AUTH_USER_MODEL)),
|
||||
('feature', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='+', to='billing.featureplan')),
|
||||
],
|
||||
options={
|
||||
'verbose_name': 'فعال\u200cسازی ریزاپ',
|
||||
'verbose_name_plural': 'فعال\u200cسازی\u200cهای ریزاپ',
|
||||
'constraints': [models.UniqueConstraint(fields=('user', 'feature'), name='unique_user_feature_activation')],
|
||||
},
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name='FeaturePlanTier',
|
||||
fields=[
|
||||
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||
('duration_months', models.PositiveSmallIntegerField(verbose_name='مدت (ماه)')),
|
||||
('gem_price', models.PositiveIntegerField(verbose_name='قیمت (جم)')),
|
||||
('feature', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='tiers', to='billing.featureplan')),
|
||||
],
|
||||
options={
|
||||
'verbose_name': 'پلن قیمتی',
|
||||
'verbose_name_plural': 'پلن\u200cهای قیمتی',
|
||||
'ordering': ['feature', 'duration_months'],
|
||||
'constraints': [models.UniqueConstraint(fields=('feature', 'duration_months'), name='unique_feature_duration')],
|
||||
},
|
||||
),
|
||||
]
|
||||
@@ -0,0 +1,42 @@
|
||||
from django.db import migrations
|
||||
|
||||
# قیمت پایهی هرکدام + پلکان تخفیف مدت (۳ماهه ≈۱۰٪ کمتر از ۳×ماهانه،
|
||||
# ۶ماهه ≈۱۷٪، ۱۲ماهه ۲۵٪) — دقیقا مطابق مثال خودِ کارفرما برای فاکتور
|
||||
# (۱۰۰۰ / ۲۷۰۰ / ۵۰۰۰)، همان الگو برای بقیه هم تعمیم داده شده.
|
||||
FEATURES = [
|
||||
("sms_bank", "بانک اساماس", 1500),
|
||||
("invoice", "فاکتور", 1000),
|
||||
("customers", "مشتریان", 500),
|
||||
("ledger", "دفتر درآمد و هزینه", 800),
|
||||
("inventory", "انبارداری", 800),
|
||||
("booking", "نوبتدهی", 600),
|
||||
]
|
||||
|
||||
|
||||
_DURATION_MULTIPLIERS = {1: 1, 3: 2.7, 6: 5, 12: 9} # ۱۰٪/۱۷٪/۲۵٪ تخفیف نسبت به ماهانه×مدت
|
||||
|
||||
|
||||
def _tier_prices(monthly: int) -> dict:
|
||||
return {months: round(monthly * multiplier) for months, multiplier in _DURATION_MULTIPLIERS.items()}
|
||||
|
||||
|
||||
def seed(apps, schema_editor):
|
||||
FeaturePlan = apps.get_model("billing", "FeaturePlan")
|
||||
FeaturePlanTier = apps.get_model("billing", "FeaturePlanTier")
|
||||
|
||||
for key, name, monthly_price in FEATURES:
|
||||
feature, _created = FeaturePlan.objects.get_or_create(key=key, defaults={"name": name})
|
||||
for months, price in _tier_prices(monthly_price).items():
|
||||
FeaturePlanTier.objects.get_or_create(
|
||||
feature=feature, duration_months=months, defaults={"gem_price": price}
|
||||
)
|
||||
|
||||
|
||||
def unseed(apps, schema_editor):
|
||||
FeaturePlan = apps.get_model("billing", "FeaturePlan")
|
||||
FeaturePlan.objects.filter(key__in=[key for key, _, _ in FEATURES]).delete()
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
dependencies = [("billing", "0001_initial")]
|
||||
operations = [migrations.RunPython(seed, unseed)]
|
||||
@@ -0,0 +1,19 @@
|
||||
from django.db import migrations
|
||||
|
||||
# ریزاپ کارگزاری کامل حذف شد — این migration پاکسازی میکند اگر روی یک DB
|
||||
# که قبلاً 0002 را اجرا کرده بود (و رکورد "brokerage" را ساخته بود) اعمال شود.
|
||||
# روی DB تازه (که 0002 دیگر "brokerage" را seed نمیکند) بیاثر است.
|
||||
|
||||
|
||||
def remove_brokerage(apps, schema_editor):
|
||||
FeaturePlan = apps.get_model("billing", "FeaturePlan")
|
||||
FeaturePlan.objects.filter(key="brokerage").delete()
|
||||
|
||||
|
||||
def noop(apps, schema_editor):
|
||||
pass
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
dependencies = [("billing", "0002_seed_feature_plans")]
|
||||
operations = [migrations.RunPython(remove_brokerage, noop)]
|
||||
@@ -0,0 +1,18 @@
|
||||
from django.db import migrations
|
||||
|
||||
# اسم نمایشی ابزار «sms_bank» برای کاربر عادی (نه فنی) واضحتر شد.
|
||||
|
||||
|
||||
def rename_forward(apps, schema_editor):
|
||||
FeaturePlan = apps.get_model("billing", "FeaturePlan")
|
||||
FeaturePlan.objects.filter(key="sms_bank").update(name="پیامک گروهی")
|
||||
|
||||
|
||||
def rename_backward(apps, schema_editor):
|
||||
FeaturePlan = apps.get_model("billing", "FeaturePlan")
|
||||
FeaturePlan.objects.filter(key="sms_bank").update(name="بانک اساماس")
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
dependencies = [("billing", "0003_remove_brokerage_feature")]
|
||||
operations = [migrations.RunPython(rename_forward, rename_backward)]
|
||||
@@ -0,0 +1,27 @@
|
||||
from django.db import migrations
|
||||
|
||||
_DURATION_MULTIPLIERS = {1: 1, 3: 2.7, 6: 5, 12: 9}
|
||||
_MONTHLY_PRICE = 900
|
||||
|
||||
|
||||
def _tier_prices() -> dict:
|
||||
return {months: round(_MONTHLY_PRICE * multiplier) for months, multiplier in _DURATION_MULTIPLIERS.items()}
|
||||
|
||||
|
||||
def seed(apps, schema_editor):
|
||||
FeaturePlan = apps.get_model("billing", "FeaturePlan")
|
||||
FeaturePlanTier = apps.get_model("billing", "FeaturePlanTier")
|
||||
|
||||
feature, _created = FeaturePlan.objects.get_or_create(key="orders", defaults={"name": "پیگیری سفارش"})
|
||||
for months, price in _tier_prices().items():
|
||||
FeaturePlanTier.objects.get_or_create(feature=feature, duration_months=months, defaults={"gem_price": price})
|
||||
|
||||
|
||||
def unseed(apps, schema_editor):
|
||||
FeaturePlan = apps.get_model("billing", "FeaturePlan")
|
||||
FeaturePlan.objects.filter(key="orders").delete()
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
dependencies = [("billing", "0004_rename_sms_bank_feature")]
|
||||
operations = [migrations.RunPython(seed, unseed)]
|
||||
Reference in New Issue
Block a user