Files
service-finder/backend/app/scripts/seed_packages.py

460 lines
14 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
#!/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_zones": {
"HU": {"monthly_price": 3000, "yearly_price": 32500, "currency": "HUF"},
"DEFAULT": {"monthly_price": 12.99, "yearly_price": 129.99, "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")
# ---------------------------------------------------------------------------
# Pricing Zones helper
# ---------------------------------------------------------------------------
def pricing_zones(
eur_monthly: float,
eur_yearly: float,
eur_credit: int = 0,
huf_monthly: int = 0,
huf_yearly: int = 0,
huf_credit: int = 0,
usd_monthly: float = 0,
usd_yearly: float = 0,
usd_credit: int = 0,
) -> dict:
"""Create a pricing_zones dict with DEFAULT (EUR), HU (HUF), and optionally USD zones."""
zones = {
"DEFAULT": {
"monthly_price": eur_monthly,
"yearly_price": eur_yearly,
"currency": "EUR",
"credit_price": eur_credit if eur_credit > 0 else None,
},
}
if huf_monthly > 0:
zones["HU"] = {
"monthly_price": huf_monthly,
"yearly_price": huf_yearly,
"currency": "HUF",
"credit_price": huf_credit if huf_credit > 0 else None,
}
if usd_monthly > 0:
zones["US"] = {
"monthly_price": usd_monthly,
"yearly_price": usd_yearly,
"currency": "USD",
"credit_price": usd_credit if usd_credit > 0 else None,
}
return zones
# ---------------------------------------------------------------------------
# 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,
},
"pricing_zones": pricing_zones(
eur_monthly=0.0,
eur_yearly=0.0,
huf_monthly=0,
huf_yearly=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,
},
"duration": {
"days": 30,
"allow_stacking": True,
},
"ad_policy": {
"show_ads": True,
"ad_free_grace_days": 0,
"max_daily_impressions": 50,
},
"marketing": {
"subtitle": "Alap szintű járműkövetés kezdőknek.",
"badge": "Ingyenes",
},
},
"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,
},
"pricing_zones": pricing_zones(
eur_monthly=4.99,
eur_yearly=49.99,
eur_credit=500,
huf_monthly=1890,
huf_yearly=18990,
huf_credit=500,
usd_monthly=5.99,
usd_yearly=59.99,
usd_credit=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,
},
"duration": {
"days": 30,
"allow_stacking": True,
},
"ad_policy": {
"show_ads": True,
"ad_free_grace_days": 3,
"max_daily_impressions": 100,
},
"marketing": {
"subtitle": "Kisebb flotta esetén ideális választás.",
"badge": "Pro",
"highlight_color": "#70BC84",
},
},
"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,
},
"pricing_zones": pricing_zones(
eur_monthly=9.99,
eur_yearly=99.99,
eur_credit=1200,
huf_monthly=3790,
huf_yearly=37990,
huf_credit=1200,
usd_monthly=11.99,
usd_yearly=119.99,
usd_credit=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,
},
"duration": {
"days": 30,
"allow_stacking": True,
},
"ad_policy": {
"show_ads": False,
"ad_free_grace_days": 0,
"max_daily_impressions": None,
},
"marketing": {
"subtitle": "VIP profi garázs kisvállalkozók számára.",
"badge": "VIP",
"highlight_color": "#F59E0B",
},
},
"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,
},
"pricing_zones": pricing_zones(
eur_monthly=29.99,
eur_yearly=299.99,
eur_credit=3000,
huf_monthly=11990,
huf_yearly=119990,
huf_credit=3000,
usd_monthly=34.99,
usd_yearly=349.99,
usd_credit=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,
},
"duration": {
"days": 30,
"allow_stacking": True,
},
"ad_policy": {
"show_ads": False,
"ad_free_grace_days": 0,
"max_daily_impressions": None,
},
"marketing": {
"subtitle": "Közepes flották számára tervezve.",
"badge": "Prémium",
"highlight_color": "#3B82F6",
},
},
"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,
},
"pricing_zones": pricing_zones(
eur_monthly=59.99,
eur_yearly=599.99,
eur_credit=6000,
huf_monthly=23990,
huf_yearly=239990,
huf_credit=6000,
usd_monthly=69.99,
usd_yearly=699.99,
usd_credit=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,
},
"duration": {
"days": 30,
"allow_stacking": True,
},
"ad_policy": {
"show_ads": False,
"ad_free_grace_days": 0,
"max_daily_impressions": None,
},
"marketing": {
"subtitle": "Nagy flották prémium menedzsmentje.",
"badge": "Plus",
"highlight_color": "#8B5CF6",
},
},
"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,
},
"pricing_zones": pricing_zones(
eur_monthly=149.99,
eur_yearly=1499.99,
eur_credit=15000,
huf_monthly=59990,
huf_yearly=599990,
huf_credit=15000,
usd_monthly=169.99,
usd_yearly=1699.99,
usd_credit=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,
},
"duration": {
"days": 30,
"allow_stacking": True,
},
"ad_policy": {
"show_ads": False,
"ad_free_grace_days": 0,
"max_daily_impressions": None,
},
"marketing": {
"subtitle": "Vállalati szintű flottairányítás.",
"badge": "VIP",
"highlight_color": "#EF4444",
},
},
"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. UPSERT: Meglévő csomagok frissítése vagy új beszúrása
from sqlalchemy.dialects.postgresql import insert as pg_insert
upserted_count = 0
for pkg in PACKAGES:
stmt = pg_insert(SubscriptionTier).values(
name=pkg["name"],
rules=pkg["rules"],
is_custom=pkg["is_custom"],
)
stmt = stmt.on_conflict_do_update(
index_elements=[SubscriptionTier.name],
set_={
"rules": stmt.excluded.rules,
"is_custom": stmt.excluded.is_custom,
}
)
await db.execute(stmt)
upserted_count += 1
logger.info(f" Upsert: {pkg['name']}")
await db.commit()
logger.info(f"{upserted_count} csomag sikeresen upsertelve.")
# 2. Visszaigazolás
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.")
# 3. 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())