admin felület fejlesztése garázs, előfizeztési csomagok
This commit is contained in:
@@ -5,17 +5,20 @@ Subscription Public API Endpoints.
|
||||
Provides:
|
||||
- GET /public — Public package catalog with dynamic pricing resolution
|
||||
based on the user's organization country (or fallback to DEFAULT zone).
|
||||
- GET /my — Current user's/org's subscription details with feature flags
|
||||
- GET /feature-flags — All feature flags resolved for the current user
|
||||
"""
|
||||
|
||||
from typing import List, Optional
|
||||
from typing import Any, Dict, List, Optional
|
||||
|
||||
from fastapi import APIRouter, Depends, HTTPException, status
|
||||
from fastapi import APIRouter, Depends, HTTPException, Query, status
|
||||
from sqlalchemy import select
|
||||
from sqlalchemy.ext.asyncio import AsyncSession
|
||||
from sqlalchemy.orm import selectinload
|
||||
|
||||
from app.api import deps
|
||||
from app.db.session import get_db
|
||||
from app.models.core_logic import SubscriptionTier
|
||||
from app.models.core_logic import SubscriptionTier, OrganizationSubscription, UserSubscription
|
||||
from app.models.identity import User
|
||||
from app.models.marketplace.organization import Organization
|
||||
from app.schemas.subscription import (
|
||||
@@ -23,6 +26,7 @@ from app.schemas.subscription import (
|
||||
SubscriptionTierResponse,
|
||||
PricingZoneModel,
|
||||
)
|
||||
from app.services.subscription_service import SubscriptionService, SUBSCRIPTION_FEATURES
|
||||
|
||||
router = APIRouter()
|
||||
|
||||
@@ -174,3 +178,179 @@ async def get_public_subscriptions(
|
||||
)
|
||||
|
||||
return response
|
||||
|
||||
|
||||
# ── P0 Feature Flag Endpoints ─────────────────────────────────────────────────
|
||||
|
||||
|
||||
@router.get(
|
||||
"/my",
|
||||
summary="Saját előfizetés részletei",
|
||||
description=(
|
||||
"Visszaadja a bejelentkezett felhasználó aktuális előfizetési adatait. "
|
||||
"Először a szervezeti előfizetést (OrganizationSubscription) ellenőrzi, "
|
||||
"ha nincs, akkor a felhasználói előfizetést (UserSubscription). "
|
||||
"Tartalmazza a tier adatokat, allowances, pricing, feature_capabilities mezőket."
|
||||
),
|
||||
)
|
||||
async def get_my_subscription(
|
||||
db: AsyncSession = Depends(get_db),
|
||||
current_user: User = Depends(deps.get_current_user),
|
||||
):
|
||||
"""
|
||||
Visszaadja a felhasználó aktuális előfizetési adatait.
|
||||
|
||||
**Feloldási sorrend:**
|
||||
1. Aktív szervezet OrganizationSubscription (ha van active_organization_id)
|
||||
2. UserSubscription (ha nincs org subscription)
|
||||
3. Fallback: alapértelmezett 'free' adatok
|
||||
|
||||
**Response struktúra:**
|
||||
```json
|
||||
{
|
||||
"subscription": {
|
||||
"tier_id": 16,
|
||||
"tier_name": "corp_premium_v1",
|
||||
"display_name": "Céges Prémium",
|
||||
"valid_from": "...",
|
||||
"valid_until": "...",
|
||||
"is_active": true,
|
||||
"allowances": {"max_vehicles": 20, ...},
|
||||
"pricing": {"monthly_price": 29.99, ...},
|
||||
"feature_capabilities": {"can_export_data": true, ...}
|
||||
},
|
||||
"tier": "premium",
|
||||
"features": {
|
||||
"export_csv": true,
|
||||
"analytics_tco": true,
|
||||
...
|
||||
},
|
||||
"source": "organization" | "user" | "default"
|
||||
}
|
||||
```
|
||||
"""
|
||||
user_id = current_user.id
|
||||
active_org_id = getattr(current_user, "active_organization_id", None)
|
||||
|
||||
subscription_data = None
|
||||
source = "default"
|
||||
|
||||
# 1. Try org subscription first
|
||||
if active_org_id:
|
||||
org_sub = await SubscriptionService.get_org_subscription_details(db, active_org_id)
|
||||
if org_sub:
|
||||
subscription_data = org_sub
|
||||
source = "organization"
|
||||
|
||||
# 2. Fallback to user subscription
|
||||
if not subscription_data:
|
||||
user_sub = await SubscriptionService.get_user_subscription_details(db, user_id)
|
||||
if user_sub:
|
||||
subscription_data = user_sub
|
||||
source = "user"
|
||||
|
||||
# 3. Resolve tier and feature flags
|
||||
user_tier = await SubscriptionService.get_user_tier(db, user_id)
|
||||
feature_flags = await SubscriptionService.get_user_feature_flags(db, user_id)
|
||||
|
||||
return {
|
||||
"subscription": subscription_data,
|
||||
"tier": user_tier,
|
||||
"features": feature_flags.get("features", {}),
|
||||
"expires_at": feature_flags.get("expires_at"),
|
||||
"source": source,
|
||||
}
|
||||
|
||||
|
||||
@router.get(
|
||||
"/feature-flags",
|
||||
summary="Feature flag-ek listázása",
|
||||
description=(
|
||||
"Visszaadja az összes feature flag állapotát a felhasználó "
|
||||
"előfizetési szintje alapján. A frontend useFeatureFlag() composable "
|
||||
"ezt a végpontot használja a funkciók engedélyezéséhez/letiltásához."
|
||||
),
|
||||
)
|
||||
async def get_feature_flags(
|
||||
db: AsyncSession = Depends(get_db),
|
||||
current_user: User = Depends(deps.get_current_user),
|
||||
):
|
||||
"""
|
||||
Visszaadja az összes feature flag állapotát.
|
||||
|
||||
**Response:**
|
||||
```json
|
||||
{
|
||||
"tier": "premium",
|
||||
"features": {
|
||||
"export_csv": true,
|
||||
"analytics_tco": true,
|
||||
"analytics_detailed": false,
|
||||
"multi_vehicle": true,
|
||||
"unlimited_vehicles": true,
|
||||
"subscription_management": true,
|
||||
"vehicle_tracking": true,
|
||||
"cost_tracking": true,
|
||||
"service_booking": true,
|
||||
"advanced_reports": true,
|
||||
"team_management": true,
|
||||
"priority_support": true,
|
||||
"white_label": false,
|
||||
"api_webhooks": false,
|
||||
"custom_integrations": false
|
||||
},
|
||||
"expires_at": "2026-07-24T12:00:00"
|
||||
}
|
||||
```
|
||||
"""
|
||||
feature_flags = await SubscriptionService.get_user_feature_flags(
|
||||
db, current_user.id
|
||||
)
|
||||
return feature_flags
|
||||
|
||||
|
||||
@router.get(
|
||||
"/check/{feature_key}",
|
||||
summary="Egy adott feature flag ellenőrzése",
|
||||
description=(
|
||||
"Ellenőrzi, hogy a felhasználó hozzáfér-e egy adott funkcióhoz. "
|
||||
"Használható a frontend által komponens szintű guard-okhoz."
|
||||
),
|
||||
)
|
||||
async def check_feature_access(
|
||||
feature_key: str,
|
||||
db: AsyncSession = Depends(get_db),
|
||||
current_user: User = Depends(deps.get_current_user),
|
||||
):
|
||||
"""
|
||||
Ellenőrzi egy adott feature elérhetőségét.
|
||||
|
||||
**Response:**
|
||||
```json
|
||||
{
|
||||
"feature_key": "analytics_tco",
|
||||
"granted": true,
|
||||
"tier": "premium",
|
||||
"required_tier": "premium"
|
||||
}
|
||||
```
|
||||
|
||||
Hibák:
|
||||
- 404: Ismeretlen feature_key
|
||||
"""
|
||||
if feature_key not in SUBSCRIPTION_FEATURES:
|
||||
raise HTTPException(
|
||||
status_code=status.HTTP_404_NOT_FOUND,
|
||||
detail=f"Unknown feature key: {feature_key}",
|
||||
)
|
||||
|
||||
user_tier = await SubscriptionService.get_user_tier(db, current_user.id)
|
||||
granted = SubscriptionService.can_access_feature(user_tier, feature_key)
|
||||
required_tier = SUBSCRIPTION_FEATURES[feature_key]
|
||||
|
||||
return {
|
||||
"feature_key": feature_key,
|
||||
"granted": granted,
|
||||
"tier": user_tier,
|
||||
"required_tier": required_tier,
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user