270 lines
8.1 KiB
Python
270 lines
8.1 KiB
Python
#!/usr/bin/env python3
|
||
"""
|
||
Seed szkript a jövőbiztos SaaS csomag-architektúra 1. fázisához.
|
||
Létrehozza a 6 alap subscription tier-t a system.subscription_tiers táblában.
|
||
|
||
Használat:
|
||
docker compose exec sf_api python3 /app/backend/app/scripts/seed_packages.py
|
||
|
||
Architektúra:
|
||
A csomagok rules JSONB oszlopa egy szabványos struktúrát követ:
|
||
{
|
||
"type": "private" | "corporate",
|
||
"pricing": {"monthly_price": float, "yearly_price": float, "currency": "EUR"},
|
||
"allowances": {"max_vehicles": int, "max_garages": int, "monthly_free_credits": int},
|
||
"entitlements": ["SRV_..."],
|
||
"affiliate": {"commission_rate_percent": int, "referral_bonus_credits": int}
|
||
}
|
||
"""
|
||
|
||
import asyncio
|
||
import json
|
||
import logging
|
||
from sqlalchemy import select, delete
|
||
from app.database import AsyncSessionLocal
|
||
from app.models.core_logic import SubscriptionTier
|
||
|
||
logging.basicConfig(
|
||
level=logging.INFO,
|
||
format="%(asctime)s [%(levelname)s] %(message)s",
|
||
)
|
||
logger = logging.getLogger("Seed-Packages")
|
||
|
||
|
||
# ---------------------------------------------------------------------------
|
||
# Csomagdefiníciók
|
||
# ---------------------------------------------------------------------------
|
||
PACKAGES = [
|
||
{
|
||
"name": "private_free_v1",
|
||
"rules": {
|
||
"type": "private",
|
||
"display_name": "Privát Ingyenes",
|
||
"pricing": {
|
||
"monthly_price": 0.0,
|
||
"yearly_price": 0.0,
|
||
"currency": "EUR",
|
||
"credit_price": 0,
|
||
},
|
||
"allowances": {
|
||
"max_vehicles": 1,
|
||
"max_garages": 1,
|
||
"monthly_free_credits": 0,
|
||
},
|
||
"entitlements": [],
|
||
"affiliate": {
|
||
"commission_rate_percent": 0,
|
||
"referral_bonus_credits": 0,
|
||
},
|
||
"lifecycle": {
|
||
"is_public": True,
|
||
},
|
||
},
|
||
"is_custom": False,
|
||
},
|
||
{
|
||
"name": "private_pro_v1",
|
||
"rules": {
|
||
"type": "private",
|
||
"display_name": "Privát Pro",
|
||
"pricing": {
|
||
"monthly_price": 4.99,
|
||
"yearly_price": 49.99,
|
||
"currency": "EUR",
|
||
"credit_price": 500,
|
||
},
|
||
"allowances": {
|
||
"max_vehicles": 3,
|
||
"max_garages": 1,
|
||
"monthly_free_credits": 50,
|
||
},
|
||
"entitlements": ["SRV_DATA_EXPORT"],
|
||
"affiliate": {
|
||
"commission_rate_percent": 10,
|
||
"referral_bonus_credits": 25,
|
||
},
|
||
"lifecycle": {
|
||
"is_public": True,
|
||
},
|
||
},
|
||
"is_custom": False,
|
||
},
|
||
{
|
||
"name": "private_vip_v1",
|
||
"rules": {
|
||
"type": "private",
|
||
"display_name": "Privát VIP",
|
||
"pricing": {
|
||
"monthly_price": 9.99,
|
||
"yearly_price": 99.99,
|
||
"currency": "EUR",
|
||
"credit_price": 1200,
|
||
},
|
||
"allowances": {
|
||
"max_vehicles": 10,
|
||
"max_garages": 1,
|
||
"monthly_free_credits": 150,
|
||
},
|
||
"entitlements": ["SRV_DATA_EXPORT", "SRV_AI_UPLOAD"],
|
||
"affiliate": {
|
||
"commission_rate_percent": 15,
|
||
"referral_bonus_credits": 50,
|
||
},
|
||
"lifecycle": {
|
||
"is_public": True,
|
||
},
|
||
},
|
||
"is_custom": False,
|
||
},
|
||
{
|
||
"name": "corp_premium_v1",
|
||
"rules": {
|
||
"type": "corporate",
|
||
"display_name": "Céges Prémium",
|
||
"pricing": {
|
||
"monthly_price": 29.99,
|
||
"yearly_price": 299.99,
|
||
"currency": "EUR",
|
||
"credit_price": 3000,
|
||
},
|
||
"allowances": {
|
||
"max_vehicles": 20,
|
||
"max_garages": 3,
|
||
"monthly_free_credits": 300,
|
||
},
|
||
"entitlements": ["SRV_DATA_EXPORT", "SRV_AI_UPLOAD"],
|
||
"affiliate": {
|
||
"commission_rate_percent": 15,
|
||
"referral_bonus_credits": 100,
|
||
},
|
||
"lifecycle": {
|
||
"is_public": True,
|
||
},
|
||
},
|
||
"is_custom": False,
|
||
},
|
||
{
|
||
"name": "corp_premium_plus_v1",
|
||
"rules": {
|
||
"type": "corporate",
|
||
"display_name": "Céges Prémium Plus",
|
||
"pricing": {
|
||
"monthly_price": 59.99,
|
||
"yearly_price": 599.99,
|
||
"currency": "EUR",
|
||
"credit_price": 6000,
|
||
},
|
||
"allowances": {
|
||
"max_vehicles": 50,
|
||
"max_garages": 10,
|
||
"monthly_free_credits": 800,
|
||
},
|
||
"entitlements": [
|
||
"SRV_DATA_EXPORT",
|
||
"SRV_AI_UPLOAD",
|
||
"SRV_ACCOUNTING_SYNC",
|
||
],
|
||
"affiliate": {
|
||
"commission_rate_percent": 20,
|
||
"referral_bonus_credits": 250,
|
||
},
|
||
"lifecycle": {
|
||
"is_public": True,
|
||
},
|
||
},
|
||
"is_custom": False,
|
||
},
|
||
{
|
||
"name": "corp_vip_v1",
|
||
"rules": {
|
||
"type": "corporate",
|
||
"display_name": "Céges VIP",
|
||
"pricing": {
|
||
"monthly_price": 149.99,
|
||
"yearly_price": 1499.99,
|
||
"currency": "EUR",
|
||
"credit_price": 15000,
|
||
},
|
||
"allowances": {
|
||
"max_vehicles": 200,
|
||
"max_garages": 50,
|
||
"monthly_free_credits": 2500,
|
||
},
|
||
"entitlements": [
|
||
"SRV_DATA_EXPORT",
|
||
"SRV_AI_UPLOAD",
|
||
"SRV_ACCOUNTING_SYNC",
|
||
"SRV_API_ACCESS",
|
||
],
|
||
"affiliate": {
|
||
"commission_rate_percent": 25,
|
||
"referral_bonus_credits": 500,
|
||
},
|
||
"lifecycle": {
|
||
"is_public": True,
|
||
},
|
||
},
|
||
"is_custom": False,
|
||
},
|
||
]
|
||
|
||
|
||
async def seed():
|
||
logger.info("=" * 60)
|
||
logger.info("Seed Packages - Advanced Subscription Tiers (Phase 1)")
|
||
logger.info("=" * 60)
|
||
|
||
async with AsyncSessionLocal() as db:
|
||
# 1. Töröljük a meglévő rekordokat (tiszta lap)
|
||
logger.info("Törlöm a meglévő subscription_tiers rekordokat...")
|
||
await db.execute(delete(SubscriptionTier))
|
||
await db.commit()
|
||
logger.info("✅ Meglévő rekordok törölve.")
|
||
|
||
# 2. Beszúrjuk a 6 új csomagot
|
||
inserted_count = 0
|
||
for pkg in PACKAGES:
|
||
tier = SubscriptionTier(
|
||
name=pkg["name"],
|
||
rules=pkg["rules"],
|
||
is_custom=pkg["is_custom"],
|
||
)
|
||
db.add(tier)
|
||
inserted_count += 1
|
||
logger.info(f" ➕ Hozzáadva: {pkg['name']}")
|
||
|
||
await db.commit()
|
||
logger.info(f"✅ {inserted_count} csomag sikeresen beszúrva.")
|
||
|
||
# 3. Visszaigazolás: listázzuk ki az összes rekordot
|
||
logger.info("-" * 60)
|
||
logger.info("Visszaigazolás - system.subscription_tiers tartalma:")
|
||
logger.info("-" * 60)
|
||
|
||
result = await db.execute(
|
||
select(SubscriptionTier).order_by(SubscriptionTier.id)
|
||
)
|
||
tiers = result.scalars().all()
|
||
|
||
for tier in tiers:
|
||
rules_json = json.dumps(tier.rules, indent=2, ensure_ascii=False)
|
||
logger.info(f"\n ID: {tier.id}")
|
||
logger.info(f" Name: {tier.name}")
|
||
logger.info(f" Is Custom: {tier.is_custom}")
|
||
logger.info(f" Rules:\n{rules_json}")
|
||
logger.info(" " + "-" * 40)
|
||
|
||
logger.info(f"\n✅ Összesen {len(tiers)} aktív csomag a rendszerben.")
|
||
|
||
# 4. JSONB példa kiírása
|
||
if tiers:
|
||
sample = tiers[0]
|
||
logger.info("=" * 60)
|
||
logger.info("JSONB PÉLDA (private_free_v1):")
|
||
logger.info("=" * 60)
|
||
logger.info(json.dumps(sample.rules, indent=2, ensure_ascii=False))
|
||
|
||
|
||
if __name__ == "__main__":
|
||
asyncio.run(seed())
|