Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 10 additions & 4 deletions src/admin/blueprints/tenants.py
Original file line number Diff line number Diff line change
Expand Up @@ -127,7 +127,10 @@ def tenant_settings(tenant_id, section=None):
"""
try:
with get_db_session() as db_session:
tenant = db_session.query(Tenant).filter_by(tenant_id=tenant_id).first()
from sqlalchemy import select

stmt = select(Tenant).filter_by(tenant_id=tenant_id)
tenant = db_session.scalars(stmt).first()
if not tenant:
flash("Tenant not found", "error")
return redirect(url_for("core.index"))
Expand All @@ -150,7 +153,8 @@ def tenant_settings(tenant_id, section=None):
# Get advertiser data for the advertisers section
from src.core.database.models import Principal

principals = db_session.query(Principal).filter_by(tenant_id=tenant_id).all()
stmt = select(Principal).filter_by(tenant_id=tenant_id)
principals = db_session.scalars(stmt).all()
advertiser_count = len(principals)
active_advertisers = len(principals) # For now, assume all are active

Expand Down Expand Up @@ -179,15 +183,17 @@ def tenant_settings(tenant_id, section=None):
# Get product counts
from src.core.database.models import Product

products = db_session.query(Product).filter_by(tenant_id=tenant_id).all()
stmt = select(Product).filter_by(tenant_id=tenant_id)
products = db_session.scalars(stmt).all()
product_count = len(products)
active_products = len([p for p in products if p.status == "active"])
draft_products = len([p for p in products if p.status == "draft"])

# Get creative formats
from src.core.database.models import CreativeFormat

creative_formats = db_session.query(CreativeFormat).filter_by(tenant_id=tenant_id).all()
stmt = select(CreativeFormat).filter_by(tenant_id=tenant_id)
creative_formats = db_session.scalars(stmt).all()

# Get admin port
admin_port = int(os.environ.get("ADMIN_UI_PORT", 8001))
Expand Down
52 changes: 32 additions & 20 deletions src/admin/services/dashboard_service.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,6 @@
import logging
from datetime import UTC, datetime, timedelta

from sqlalchemy.orm import joinedload

from src.admin.services.business_activity_service import get_business_activities
from src.admin.services.media_buy_readiness_service import MediaBuyReadinessService
from src.core.database.database_session import get_db_session
Expand All @@ -35,7 +33,10 @@ def get_tenant(self) -> Tenant | None:
"""Get tenant object, cached for this service instance."""
if self._tenant is None:
with get_db_session() as db_session:
self._tenant = db_session.query(Tenant).filter_by(tenant_id=self.tenant_id).first()
from sqlalchemy import select

stmt = select(Tenant).filter_by(tenant_id=self.tenant_id)
self._tenant = db_session.scalars(stmt).first()
return self._tenant

def get_dashboard_metrics(self) -> dict[str, any]:
Expand All @@ -55,16 +56,22 @@ def get_dashboard_metrics(self) -> dict[str, any]:
readiness_summary = MediaBuyReadinessService.get_tenant_readiness_summary(self.tenant_id)

# Core business metrics
principals_count = db_session.query(Principal).filter_by(tenant_id=self.tenant_id).count()
products_count = db_session.query(Product).filter_by(tenant_id=self.tenant_id).count()
from sqlalchemy import func, select

principals_count = db_session.scalar(
select(func.count()).select_from(Principal).where(Principal.tenant_id == self.tenant_id)
)
products_count = db_session.scalar(
select(func.count()).select_from(Product).where(Product.tenant_id == self.tenant_id)
)

# Calculate total spend from live and completed media buys
total_spend_buys = (
db_session.query(MediaBuy)
stmt = (
select(MediaBuy)
.filter_by(tenant_id=self.tenant_id)
.filter(MediaBuy.status.in_(["active", "completed"]))
.all()
.where(MediaBuy.status.in_(["active", "completed"]))
)
total_spend_buys = db_session.scalars(stmt).all()
total_spend_amount = float(sum(buy.budget or 0 for buy in total_spend_buys))

# Revenue trend data (last 30 days)
Expand Down Expand Up @@ -124,15 +131,18 @@ def get_recent_media_buys(self, limit: int = 10) -> list[MediaBuy]:
"""Get recent media buys with relationships loaded and readiness state."""
try:
with get_db_session() as db_session:
recent_buys = (
db_session.query(MediaBuy)
.filter(MediaBuy.tenant_id == self.tenant_id)
.filter(MediaBuy.media_buy_id.isnot(None)) # Defensive: ensure valid ID
from sqlalchemy import select
from sqlalchemy.orm import joinedload

stmt = (
select(MediaBuy)
.where(MediaBuy.tenant_id == self.tenant_id)
.where(MediaBuy.media_buy_id.isnot(None)) # Defensive: ensure valid ID
.options(joinedload(MediaBuy.principal)) # Eager load to avoid N+1
.order_by(MediaBuy.created_at.desc())
.limit(limit)
.all()
)
recent_buys = db_session.scalars(stmt).all()

# Transform for template consumption
for media_buy in recent_buys:
Expand Down Expand Up @@ -171,14 +181,16 @@ def _calculate_revenue_trend(self, db_session, days: int = 30) -> list[dict[str,
date = today - timedelta(days=days - 1 - i)

# Calculate revenue for this date
daily_buys = (
db_session.query(MediaBuy)
from sqlalchemy import select

stmt = (
select(MediaBuy)
.filter_by(tenant_id=self.tenant_id)
.filter(MediaBuy.start_date <= date)
.filter(MediaBuy.end_date >= date)
.filter(MediaBuy.status.in_(["active", "completed"]))
.all()
.where(MediaBuy.start_date <= date)
.where(MediaBuy.end_date >= date)
.where(MediaBuy.status.in_(["active", "completed"]))
)
daily_buys = db_session.scalars(stmt).all()

daily_revenue = 0
for buy in daily_buys:
Expand Down
Loading
Loading