RABAC felépítése megtörtént ill hirdetési portál alapok lerakva

This commit is contained in:
Roo
2026-06-19 06:06:34 +00:00
parent fe3c32597d
commit 9ba2d9180d
30 changed files with 4336 additions and 76 deletions

View File

@@ -494,9 +494,11 @@ class AssetService:
Get the vehicle limit for a user, checking:
1. Subscription tier JSONB rules['allowances']['max_vehicles'] (PRIMARY source of truth)
2. Organization-level base_asset_limit (fallback if no user subscription)
3. Config-based limits (legacy fallback)
3. P0 BOOSTER: extra_allowances from finance.org_subscriptions (additive on top of tier)
4. Config-based limits (legacy fallback)
P0: The subscription_tier JSONB rules are now the Single Source of Truth.
P0 Booster: extra_allowances.extra_vehicles is added on top of the tier limit.
Legacy string-based subscription_plan lookups have been removed.
Args:
@@ -508,7 +510,7 @@ class AssetService:
Maximum allowed vehicles
"""
from app.models.identity import User
from app.models.core_logic import UserSubscription, SubscriptionTier
from app.models.core_logic import UserSubscription, SubscriptionTier, OrganizationSubscription
from app.models.marketplace.organization import Organization
from app.services.config_service import config
@@ -577,7 +579,33 @@ class AssetService:
except Exception as e:
logger.debug(f"Could not read org subscription tier limit for org {org_id}: {e}")
# ── 3. CONFIG-BASED LIMIT (legacy fallback, role-based only) ──
# ── 3. P0 BOOSTER: extra_allowances from finance.org_subscriptions ──
# Extra allowances are additive on top of the tier limit.
# Read from the active org subscription's extra_allowances JSONB.
extra_vehicles = 0
try:
org_sub_stmt = (
select(OrganizationSubscription.extra_allowances)
.where(
OrganizationSubscription.org_id == org_id,
OrganizationSubscription.is_active == True
)
.limit(1)
)
org_sub_result = await db.execute(org_sub_stmt)
extra_allowances = org_sub_result.scalar_one_or_none()
if extra_allowances and isinstance(extra_allowances, dict):
extra_vehicles = int(extra_allowances.get('extra_vehicles', 0))
if extra_vehicles > 0:
logger.info(
f"[P0 BOOSTER] Extra vehicles for org {org_id}: "
f"extra_vehicles={extra_vehicles} (from extra_allowances JSONB)"
)
except Exception as e:
logger.debug(f"Could not read extra_allowances for org {org_id}: {e}")
# ── 4. CONFIG-BASED LIMIT (legacy fallback, role-based only) ──
config_limit = None
try:
limits = await config.get_setting(db, "VEHICLE_LIMIT")
@@ -591,16 +619,20 @@ class AssetService:
if config_limit is None:
config_limit = 1 # absolute fallback
# ── 4. FINAL: Take the HIGHEST of all applicable limits ──
# ── 5. FINAL: Take the HIGHEST of all applicable limits, then ADD boosters ──
final_limit = config_limit
if org_limit is not None:
final_limit = max(final_limit, org_limit)
if subscription_limit is not None:
final_limit = max(final_limit, subscription_limit)
# Add extra_allowances on top of the base limit
final_limit = final_limit + extra_vehicles
logger.info(
f"[P0] Vehicle limit for user {user_id} (role={user_role}): "
f"subscription_tier={subscription_limit}, org={org_limit}, config={config_limit}, "
f"subscription_tier={subscription_limit}, org={org_limit}, "
f"extra_vehicles={extra_vehicles}, config={config_limit}, "
f"final={final_limit}"
)

View File

@@ -727,6 +727,9 @@ async def upgrade_subscription(
"""
Felhasználó előfizetésének frissítése (csomagváltás).
P0 Stacking Feature: A duration_days mezőt a tier.rules-ból olvassa ki,
és a valid_until számításánál időhalmozást (stacking) alkalmaz.
Args:
db: Database session
user_id: Felhasználó ID
@@ -735,7 +738,7 @@ async def upgrade_subscription(
Returns:
Dict: Tranzakció részletei és az új előfizetés információi
"""
from app.models.core_logic import SubscriptionTier
from app.models.core_logic import SubscriptionTier, UserSubscription
from app.models.identity import User
# 1. Ellenőrizze, hogy a cél csomag létezik-e
@@ -746,23 +749,67 @@ async def upgrade_subscription(
if not tier:
raise ValueError(f"Subscription tier '{target_package}' not found")
# ── P0 STACKING: duration_days kiolvasása a tier.rules-ból ──
duration_days = 30 # alapértelmezett 30 nap
allow_stacking = True
if tier.rules:
duration_config = tier.rules.get("duration", {})
if isinstance(duration_config, dict):
duration_days = duration_config.get("days", 30)
allow_stacking = duration_config.get("allow_stacking", True)
now = datetime.utcnow()
# 2. Számítsa ki az árát a csomagnak (egyszerűsítve: fix ár a tier.rules-ból)
price = tier.rules.get("price", 0.0) if tier.rules else 0.0
if price <= 0:
# Ingyenes csomag, nincs levonás
logger.info(f"Upgrading user {user_id} to free tier {target_package}")
# Frissítse a felhasználó subscription_plan mezőjét
user_stmt = select(User).where(User.id == user_id)
user_result = await db.execute(user_stmt)
user = user_result.scalar_one()
user.subscription_plan = target_package
user.subscription_expires_at = datetime.utcnow() + timedelta(days=30) # 30 nap
# ── P0 STACKING: user_subscriptions tábla kezelése ──
# Lekérdezzük a meglévő aktív user subscription-t
us_stmt = select(UserSubscription).where(
UserSubscription.user_id == user_id,
UserSubscription.is_active == True
)
us_result = await db.execute(us_stmt)
existing_us = us_result.scalar_one_or_none()
if existing_us:
existing_us.is_active = False
# Stacking számítás
if existing_us and allow_stacking and existing_us.valid_until and existing_us.valid_until > now:
new_valid_until = existing_us.valid_until + timedelta(days=duration_days)
else:
new_valid_until = now + timedelta(days=duration_days)
# Új UserSubscription rekord
new_us = UserSubscription(
user_id=user_id,
tier_id=tier.id,
valid_from=now,
valid_until=new_valid_until,
is_active=True
)
db.add(new_us)
user.subscription_expires_at = new_valid_until
return {
"success": True,
"message": f"Upgraded to {target_package} (free)",
"new_plan": target_package,
"price_paid": 0.0
"price_paid": 0.0,
"valid_until": new_valid_until.isoformat(),
"duration_days": duration_days,
"stacking_applied": allow_stacking and bool(existing_us and existing_us.valid_until and existing_us.valid_until > now)
}
# 3. Ár kiszámítása a PricingCalculator segítségével
@@ -789,15 +836,51 @@ async def upgrade_subscription(
# 5. Frissítse a felhasználó előfizetési adatait
user.subscription_plan = target_package
user.subscription_expires_at = datetime.utcnow() + timedelta(days=30) # 30 nap
logger.info(f"User {user_id} upgraded to {target_package} for {final_price} EUR")
# ── P0 STACKING: user_subscriptions tábla kezelése ──
us_stmt = select(UserSubscription).where(
UserSubscription.user_id == user_id,
UserSubscription.is_active == True
)
us_result = await db.execute(us_stmt)
existing_us = us_result.scalar_one_or_none()
if existing_us:
existing_us.is_active = False
# Stacking számítás
if existing_us and allow_stacking and existing_us.valid_until and existing_us.valid_until > now:
new_valid_until = existing_us.valid_until + timedelta(days=duration_days)
else:
new_valid_until = now + timedelta(days=duration_days)
# Új UserSubscription rekord
new_us = UserSubscription(
user_id=user_id,
tier_id=tier.id,
valid_from=now,
valid_until=new_valid_until,
is_active=True
)
db.add(new_us)
user.subscription_expires_at = new_valid_until
logger.info(
f"User {user_id} upgraded to {target_package} for {final_price} EUR, "
f"valid_until={new_valid_until.isoformat()}, "
f"duration_days={duration_days}, "
f"stacking={allow_stacking}"
)
return {
"success": True,
"transaction": transaction,
"new_plan": target_package,
"price_paid": final_price,
"valid_until": new_valid_until.isoformat(),
"duration_days": duration_days,
"stacking_applied": allow_stacking and bool(existing_us and existing_us.valid_until and existing_us.valid_until > now),
"expires_at": user.subscription_expires_at.isoformat()
}
@@ -816,6 +899,12 @@ async def upgrade_org_subscription(
subscription_tier_id FK on the Organization record, and also creates/
updates a record in finance.org_subscriptions for audit trail.
P0 Stacking Feature: A duration_days mezőt a tier.rules-ból olvassa ki,
és a valid_until számításánál időhalmozást (stacking) alkalmaz:
- Ha a meglévő előfizetés még aktív (valid_until > NOW):
új valid_until = régi valid_until + duration_days
- Ha lejárt vagy nincs: új valid_until = NOW + duration_days
Args:
db: Database session
org_id: Organization ID
@@ -860,24 +949,54 @@ async def upgrade_org_subscription(
sub_result = await db.execute(sub_stmt)
existing_sub = sub_result.scalar_one_or_none()
# ── P0 STACKING: duration_days kiolvasása a tier.rules-ból ──
duration_days = 30 # alapértelmezett 30 nap
allow_stacking = True
if tier.rules:
duration_config = tier.rules.get("duration", {})
if isinstance(duration_config, dict):
duration_days = duration_config.get("days", 30)
allow_stacking = duration_config.get("allow_stacking", True)
now = datetime.utcnow()
if existing_sub:
# Deaktiváljuk a régit
existing_sub.is_active = False
existing_sub.valid_until = datetime.utcnow()
existing_sub.valid_until = now
# Új aktív subscription rekord
# ── P0 STACKING: valid_until számítás időhalmozással ──
if existing_sub and allow_stacking and existing_sub.valid_until and existing_sub.valid_until > now:
# Stacking: a meglévő valid_until-hoz hozzáadjuk a duration_days-t
new_valid_until = existing_sub.valid_until + timedelta(days=duration_days)
logger.info(
f"STACKING: org_id={org_id} existing valid_until={existing_sub.valid_until} "
f"+ {duration_days} days = {new_valid_until}"
)
else:
# Nincs stacking: mostól számítva + duration_days
new_valid_until = now + timedelta(days=duration_days)
# Új aktív subscription rekord stackinggel számolt valid_until-lal
new_sub = OrganizationSubscription(
org_id=org_id,
tier_id=tier_id,
valid_from=datetime.utcnow(),
valid_from=now,
valid_until=new_valid_until,
is_active=True
)
db.add(new_sub)
# Frissítsük a szervezet denormalizált mezőit is
org.subscription_expires_at = new_valid_until
logger.info(
f"Org subscription upgraded: org_id={org_id}, "
f"tier={tier.name} (id={tier_id}), "
f"max_vehicles={max_vehicles}, "
f"valid_until={new_valid_until.isoformat()}, "
f"duration_days={duration_days}, "
f"stacking={allow_stacking}, "
f"actor={actor_user_id}"
)
@@ -887,6 +1006,9 @@ async def upgrade_org_subscription(
"tier_id": tier_id,
"tier_name": tier.name,
"max_vehicles": max_vehicles,
"valid_until": new_valid_until.isoformat(),
"duration_days": duration_days,
"stacking_applied": allow_stacking and bool(existing_sub and existing_sub.valid_until and existing_sub.valid_until > now),
"message": f"Organization {org_id} upgraded to {tier.name}"
}