RABAC felépítése megtörtént ill hirdetési portál alapok lerakva
This commit is contained in:
@@ -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}"
|
||||
)
|
||||
|
||||
|
||||
@@ -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}"
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user