admin felület bekötése. pontosítások2
This commit is contained in:
@@ -52,6 +52,19 @@ class OrgSubscriptionUpdate(BaseModel):
|
||||
description="Egyedi lejárati dátum (pl. 2-5 éves B2B deal esetén). "
|
||||
"Ha None, a csomag duration.days alapján számolódik."
|
||||
)
|
||||
# ── P0 ADD-ON UPGRADE: Extra allowances (add-ons) ──
|
||||
extra_vehicles: int = Field(
|
||||
default=0, ge=0,
|
||||
description="Extra jármű kvóta a csomag keretein felül (add-on)."
|
||||
)
|
||||
extra_branches: int = Field(
|
||||
default=0, ge=0,
|
||||
description="Extra telephely kvóta a csomag keretein felül (add-on)."
|
||||
)
|
||||
extra_users: int = Field(
|
||||
default=0, ge=0,
|
||||
description="Extra dolgozó kvóta a csomag keretein felül (add-on)."
|
||||
)
|
||||
|
||||
|
||||
class OrgSubscriptionResponse(BaseModel):
|
||||
@@ -122,6 +135,19 @@ class SubscriptionSummary(BaseModel):
|
||||
is_active: bool = True
|
||||
asset_count: int = 0
|
||||
asset_limit: int = 1
|
||||
# ── P0 ADD-ON UPGRADE: Branch & User limits ──
|
||||
branch_limit: int = 0
|
||||
user_limit: int = 0
|
||||
# ── P0 ADD-ON UPGRADE: Extra allowances (add-ons) ──
|
||||
extra_allowances: dict = {}
|
||||
|
||||
|
||||
class BranchBrief(BaseModel):
|
||||
"""Rövid telephely adatok a frontend számára."""
|
||||
id: int
|
||||
name: str
|
||||
city: Optional[str] = None
|
||||
is_active: bool = True
|
||||
|
||||
|
||||
class GarageDetailsResponse(BaseModel):
|
||||
@@ -166,8 +192,14 @@ class GarageDetailsResponse(BaseModel):
|
||||
# Meta
|
||||
created_at: Optional[str] = None
|
||||
member_count: int = 0
|
||||
# P0: Owner user ID for frontend display
|
||||
owner_user_id: Optional[int] = None
|
||||
# P0: Owner person ID for frontend display
|
||||
owner_person_id: Optional[int] = None
|
||||
# P0: Full member list with nested person data
|
||||
members: List[OrganizationMemberResponse] = []
|
||||
# ── P0 ADD-ON UPGRADE: Branches list for utilization display ──
|
||||
branches: List[BranchBrief] = []
|
||||
|
||||
|
||||
# =============================================================================
|
||||
@@ -217,7 +249,18 @@ async def list_organizations(
|
||||
if status_filter:
|
||||
base_query = base_query.where(Organization.status == status_filter)
|
||||
if org_type_filter:
|
||||
base_query = base_query.where(Organization.org_type == org_type_filter)
|
||||
if org_type_filter == "corporate":
|
||||
# P0 HOTFIX: "corporate" is a UI category, not a DB enum value.
|
||||
# The DB enum (fleet.orgtype) has: individual, business, fleet_owner,
|
||||
# service, service_provider, club. "corporate" means all non-individual types.
|
||||
from app.models.marketplace.organization import OrgType
|
||||
corporate_types = [
|
||||
t.value for t in OrgType
|
||||
if t.value != OrgType.individual.value
|
||||
]
|
||||
base_query = base_query.where(Organization.org_type.in_(corporate_types))
|
||||
else:
|
||||
base_query = base_query.where(Organization.org_type == org_type_filter)
|
||||
if tier_name_filter:
|
||||
from app.models.core_logic import SubscriptionTier
|
||||
base_query = base_query.join(SubscriptionTier, Organization.subscription_tier_id == SubscriptionTier.id)
|
||||
@@ -395,13 +438,15 @@ async def get_organization_details(
|
||||
detail=f"Szervezet nem található ID-vel: {org_id}",
|
||||
)
|
||||
|
||||
# 2. Aktív előfizetés lekérése
|
||||
# 2. Aktív előfizetés lekérése (P0 ADD-ON: valid_until >= now() check)
|
||||
now = datetime.utcnow()
|
||||
sub_stmt = (
|
||||
select(OrganizationSubscription)
|
||||
.options(selectinload(OrganizationSubscription.tier))
|
||||
.where(
|
||||
OrganizationSubscription.org_id == org_id,
|
||||
OrganizationSubscription.is_active == True,
|
||||
OrganizationSubscription.valid_until >= now,
|
||||
)
|
||||
.order_by(OrganizationSubscription.id.desc())
|
||||
.limit(1)
|
||||
@@ -409,6 +454,33 @@ async def get_organization_details(
|
||||
sub_result = await db.execute(sub_stmt)
|
||||
active_sub = sub_result.scalar_one_or_none()
|
||||
|
||||
# 2b. P0 ADD-ON: Valós járműszám lekérése a fleet táblából
|
||||
from app.models.fleet.vehicle import Vehicle # noqa: E402
|
||||
vehicle_count_stmt = select(func.count(Vehicle.id)).where(
|
||||
Vehicle.organization_id == org_id,
|
||||
Vehicle.is_deleted == False,
|
||||
)
|
||||
vehicle_count_result = await db.execute(vehicle_count_stmt)
|
||||
asset_count = vehicle_count_result.scalar() or 0
|
||||
|
||||
# 2c. P0 ADD-ON: Telephelyek (branches) lekérése
|
||||
from app.models.fleet.organization import Branch # noqa: E402
|
||||
branches_stmt = select(Branch).where(
|
||||
Branch.organization_id == org_id,
|
||||
Branch.is_deleted == False,
|
||||
).order_by(Branch.name)
|
||||
branches_result = await db.execute(branches_stmt)
|
||||
branch_rows = branches_result.scalars().all()
|
||||
branches_list = [
|
||||
BranchBrief(
|
||||
id=b.id,
|
||||
name=b.name,
|
||||
city=b.city,
|
||||
is_active=b.is_active,
|
||||
)
|
||||
for b in branch_rows
|
||||
]
|
||||
|
||||
# 3. Tagok lekérése eager loading-gal (User + Person)
|
||||
members_stmt = (
|
||||
select(OrganizationMember)
|
||||
@@ -440,36 +512,59 @@ async def get_organization_details(
|
||||
contact_result = await db.execute(contact_stmt)
|
||||
contact = contact_result.scalar_one_or_none()
|
||||
|
||||
# 5. Subscription összefoglaló
|
||||
# 5. Subscription összefoglaló — P0 ADD-ON UPGRADE
|
||||
# Fix: explicit dict.get() instead of `or` (bugfix: 0 is falsy in Python)
|
||||
# Add: extra_allowances math (Base + Extra)
|
||||
subscription_summary = None
|
||||
if active_sub and active_sub.tier:
|
||||
rules = active_sub.tier.rules or {}
|
||||
asset_limit = (
|
||||
rules.get("max_vehicles")
|
||||
or active_sub.tier.feature_capabilities.get("max_vehicles")
|
||||
or 1
|
||||
)
|
||||
fc = active_sub.tier.feature_capabilities or {}
|
||||
extra = active_sub.extra_allowances or {}
|
||||
|
||||
# Base limits from tier rules (with explicit .get() — no `or` bug)
|
||||
base_vehicles = rules.get("max_vehicles", fc.get("max_vehicles", 1))
|
||||
base_branches = rules.get("max_branches", fc.get("max_branches", 0))
|
||||
base_users = rules.get("max_users", fc.get("max_users", 0))
|
||||
|
||||
# Extra allowances (add-ons)
|
||||
extra_vehicles = extra.get("extra_vehicles", 0) or 0
|
||||
extra_branches = extra.get("extra_branches", 0) or 0
|
||||
extra_users = extra.get("extra_users", 0) or 0
|
||||
|
||||
# Total = Base + Extra
|
||||
asset_limit = base_vehicles + extra_vehicles
|
||||
branch_limit = base_branches + extra_branches
|
||||
user_limit = base_users + extra_users
|
||||
|
||||
subscription_summary = SubscriptionSummary(
|
||||
tier_name=active_sub.tier.name,
|
||||
tier_level=active_sub.tier.tier_level,
|
||||
valid_from=active_sub.valid_from.isoformat() if active_sub.valid_from else None,
|
||||
expires_at=active_sub.valid_until.isoformat() if active_sub.valid_until else None,
|
||||
is_active=active_sub.is_active,
|
||||
asset_count=0,
|
||||
asset_count=asset_count,
|
||||
asset_limit=asset_limit,
|
||||
branch_limit=branch_limit,
|
||||
user_limit=user_limit,
|
||||
extra_allowances=extra,
|
||||
)
|
||||
elif org.subscription_tier:
|
||||
rules = org.subscription_tier.rules or {}
|
||||
asset_limit = (
|
||||
rules.get("max_vehicles")
|
||||
or org.subscription_tier.feature_capabilities.get("max_vehicles")
|
||||
or 1
|
||||
)
|
||||
fc = org.subscription_tier.feature_capabilities or {}
|
||||
extra = {}
|
||||
|
||||
base_vehicles = rules.get("max_vehicles", fc.get("max_vehicles", 1))
|
||||
base_branches = rules.get("max_branches", fc.get("max_branches", 0))
|
||||
base_users = rules.get("max_users", fc.get("max_users", 0))
|
||||
|
||||
subscription_summary = SubscriptionSummary(
|
||||
tier_name=org.subscription_tier.name,
|
||||
tier_level=org.subscription_tier.tier_level,
|
||||
expires_at=org.subscription_expires_at.isoformat() if org.subscription_expires_at else None,
|
||||
asset_limit=asset_limit,
|
||||
asset_count=asset_count,
|
||||
asset_limit=base_vehicles,
|
||||
branch_limit=base_branches,
|
||||
user_limit=base_users,
|
||||
)
|
||||
|
||||
# 6. Kapcsolattartó adatok
|
||||
@@ -524,6 +619,7 @@ async def get_organization_details(
|
||||
# Get email from the user record
|
||||
email = m.user.email if m.user else None
|
||||
person_data = PersonBrief(
|
||||
id=person_obj.id,
|
||||
first_name=person_obj.first_name or "",
|
||||
last_name=person_obj.last_name or "",
|
||||
email=email,
|
||||
@@ -554,6 +650,7 @@ async def get_organization_details(
|
||||
# we still provide an empty PersonBrief so the frontend never crashes
|
||||
# on null person access.
|
||||
owner_person_data = PersonBrief(
|
||||
id=owner_person.id if owner_person else None,
|
||||
first_name=owner_person.first_name or "" if owner_person else "",
|
||||
last_name=owner_person.last_name or "" if owner_person else "",
|
||||
email=owner_email,
|
||||
@@ -629,7 +726,12 @@ async def get_organization_details(
|
||||
primary_contact=primary_contact,
|
||||
created_at=org.created_at.isoformat() if org.created_at else None,
|
||||
member_count=member_count,
|
||||
# P0: Expose owner user ID and person ID for frontend display
|
||||
owner_user_id=owner.id if owner else None,
|
||||
owner_person_id=owner_person.id if owner_person else None,
|
||||
members=members_list,
|
||||
# ── P0 ADD-ON UPGRADE: Branches list ──
|
||||
branches=branches_list,
|
||||
)
|
||||
|
||||
|
||||
@@ -939,17 +1041,27 @@ async def update_org_subscription(
|
||||
from datetime import timedelta
|
||||
valid_until = now + timedelta(days=days)
|
||||
|
||||
# 5. Létrehozzuk az új subscription rekordot
|
||||
# 5. P0 ADD-ON: Összeállítjuk az extra_allowances JSONB-t
|
||||
extra_allowances = {}
|
||||
if payload.extra_vehicles > 0:
|
||||
extra_allowances["extra_vehicles"] = payload.extra_vehicles
|
||||
if payload.extra_branches > 0:
|
||||
extra_allowances["extra_branches"] = payload.extra_branches
|
||||
if payload.extra_users > 0:
|
||||
extra_allowances["extra_users"] = payload.extra_users
|
||||
|
||||
# 6. Létrehozzuk az új subscription rekordot
|
||||
new_sub = OrganizationSubscription(
|
||||
org_id=org_id,
|
||||
tier_id=payload.tier_id,
|
||||
valid_from=now,
|
||||
valid_until=valid_until,
|
||||
is_active=True,
|
||||
extra_allowances=extra_allowances,
|
||||
)
|
||||
db.add(new_sub)
|
||||
|
||||
# 6. Frissítjük a Organization denormalizált mezőit is
|
||||
# 7. Frissítjük a Organization denormalizált mezőit is
|
||||
org.subscription_tier_id = payload.tier_id
|
||||
org.subscription_expires_at = valid_until
|
||||
org.subscription_plan = tier.name
|
||||
@@ -960,7 +1072,8 @@ async def update_org_subscription(
|
||||
logger.info(
|
||||
f"Admin {current_user.id} ({current_user.email}) updated subscription for org {org_id}: "
|
||||
f"tier_id={payload.tier_id}, tier_name={tier.name}, "
|
||||
f"valid_until={valid_until.isoformat()}"
|
||||
f"valid_until={valid_until.isoformat()}, "
|
||||
f"extra_allowances={extra_allowances}"
|
||||
)
|
||||
|
||||
return {
|
||||
@@ -974,6 +1087,7 @@ async def update_org_subscription(
|
||||
"valid_from": new_sub.valid_from.isoformat() if new_sub.valid_from else None,
|
||||
"valid_until": new_sub.valid_until.isoformat() if new_sub.valid_until else None,
|
||||
"is_active": new_sub.is_active,
|
||||
"extra_allowances": extra_allowances,
|
||||
},
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user