Initial commit: VoIdeaAI - voice-first AI idea assistant

This commit is contained in:
2026-05-13 12:51:42 +03:00
commit 688d043dad
421 changed files with 47915 additions and 0 deletions
+110
View File
@@ -0,0 +1,110 @@
"""Tariff service for VoIdea."""
from decimal import Decimal
from typing import Any, Optional
from uuid import UUID
from sqlalchemy import select
from sqlalchemy.ext.asyncio import AsyncSession
from app.models.tariff import TariffPlan, UserSubscription
class TariffService:
def __init__(self, db: AsyncSession):
self.db = db
# ── Plans ──
async def list_plans(self, active_only: bool = True) -> list[TariffPlan]:
query = select(TariffPlan)
if active_only:
query = query.where(TariffPlan.is_active.is_(True))
query = query.order_by(TariffPlan.sort_order)
result = await self.db.execute(query)
return list(result.scalars().all())
async def get_plan_by_id(self, plan_id: UUID) -> Optional[TariffPlan]:
return await self.db.get(TariffPlan, plan_id)
async def get_plan_by_code(self, code: str) -> Optional[TariffPlan]:
result = await self.db.execute(
select(TariffPlan).where(TariffPlan.code == code)
)
return result.scalar_one_or_none()
async def create_plan(
self,
name: str,
code: str,
description: Optional[str] = None,
price_monthly: Decimal = Decimal("0"),
price_yearly: Optional[Decimal] = None,
features: Optional[dict[str, Any]] = None,
is_active: bool = True,
sort_order: int = 0,
) -> TariffPlan:
plan = TariffPlan(
name=name,
code=code,
description=description,
price_monthly=price_monthly,
price_yearly=price_yearly,
features=features,
is_active=is_active,
sort_order=sort_order,
)
self.db.add(plan)
await self.db.commit()
await self.db.refresh(plan)
return plan
async def update_plan(
self, plan_id: UUID, updates: dict[str, Any]
) -> Optional[TariffPlan]:
plan = await self.get_plan_by_id(plan_id)
if not plan:
return None
for key, value in updates.items():
if hasattr(plan, key) and key not in ("id", "code", "created_at"):
setattr(plan, key, value)
await self.db.commit()
await self.db.refresh(plan)
return plan
async def delete_plan(self, plan_id: UUID) -> bool:
plan = await self.get_plan_by_id(plan_id)
if not plan:
return False
await self.db.delete(plan)
await self.db.commit()
return True
# ── Subscriptions ──
async def get_user_subscription(self, user_id: UUID) -> Optional[UserSubscription]:
result = await self.db.execute(
select(UserSubscription).where(UserSubscription.user_id == user_id)
)
return result.scalar_one_or_none()
async def assign_plan(self, user_id: UUID, plan_code: str) -> Optional[UserSubscription]:
plan = await self.get_plan_by_code(plan_code)
if not plan:
return None
sub = await self.get_user_subscription(user_id)
if sub:
sub.plan_id = plan.id
sub.status = "active"
else:
sub = UserSubscription(
user_id=user_id,
plan_id=plan.id,
status="active",
)
self.db.add(sub)
await self.db.commit()
await self.db.refresh(sub)
return sub