The merchant dashboard was showing subscription count as "Total Stores". Add get_merchant_metrics() to MetricsProviderProtocol and implement it in tenancy, billing, and customer providers. Dashboard now fetches real stats from a new /merchants/core/dashboard/stats endpoint and displays 4 cards: active subscriptions, total stores, customers, team members. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
155 lines
4.5 KiB
Python
155 lines
4.5 KiB
Python
# app/modules/billing/services/billing_metrics.py
|
|
"""
|
|
Metrics provider for the billing module.
|
|
|
|
Provides metrics for:
|
|
- Subscription counts (total, active, trial)
|
|
"""
|
|
|
|
import logging
|
|
|
|
from sqlalchemy import func
|
|
from sqlalchemy.orm import Session
|
|
|
|
from app.modules.contracts.metrics import (
|
|
MetricsContext,
|
|
MetricValue,
|
|
)
|
|
|
|
logger = logging.getLogger(__name__)
|
|
|
|
|
|
class BillingMetricsProvider:
|
|
"""
|
|
Metrics provider for billing module.
|
|
|
|
Provides subscription metrics at the platform level.
|
|
"""
|
|
|
|
@property
|
|
def metrics_category(self) -> str:
|
|
return "billing"
|
|
|
|
def get_store_metrics(
|
|
self,
|
|
db: Session,
|
|
store_id: int,
|
|
context: MetricsContext | None = None,
|
|
) -> list[MetricValue]:
|
|
"""
|
|
Get metrics for a specific store.
|
|
|
|
Subscriptions are merchant-level, not store-level, so no store metrics.
|
|
"""
|
|
return []
|
|
|
|
def get_platform_metrics(
|
|
self,
|
|
db: Session,
|
|
platform_id: int,
|
|
context: MetricsContext | None = None,
|
|
) -> list[MetricValue]:
|
|
"""
|
|
Get subscription metrics aggregated for a platform.
|
|
|
|
Provides:
|
|
- Total subscriptions
|
|
- Active subscriptions (active + trial)
|
|
- Trial subscriptions
|
|
"""
|
|
from app.modules.billing.models import MerchantSubscription, SubscriptionStatus
|
|
|
|
try:
|
|
total_subs = (
|
|
db.query(func.count(MerchantSubscription.id)).scalar() or 0
|
|
)
|
|
|
|
active_subs = (
|
|
db.query(func.count(MerchantSubscription.id))
|
|
.filter(MerchantSubscription.status.in_(["active", "trial"]))
|
|
.scalar()
|
|
or 0
|
|
)
|
|
|
|
trial_subs = (
|
|
db.query(func.count(MerchantSubscription.id))
|
|
.filter(MerchantSubscription.status == SubscriptionStatus.TRIAL.value)
|
|
.scalar()
|
|
or 0
|
|
)
|
|
|
|
return [
|
|
MetricValue(
|
|
key="billing.total_subscriptions",
|
|
value=total_subs,
|
|
label="Total Subscriptions",
|
|
category="billing",
|
|
icon="credit-card",
|
|
description="Total number of merchant subscriptions",
|
|
),
|
|
MetricValue(
|
|
key="billing.active_subscriptions",
|
|
value=active_subs,
|
|
label="Active Subscriptions",
|
|
category="billing",
|
|
icon="check-circle",
|
|
description="Subscriptions with active or trial status",
|
|
),
|
|
MetricValue(
|
|
key="billing.trial_subscriptions",
|
|
value=trial_subs,
|
|
label="Trial Subscriptions",
|
|
category="billing",
|
|
icon="clock",
|
|
description="Subscriptions currently in trial period",
|
|
),
|
|
]
|
|
except Exception as e:
|
|
logger.warning(f"Failed to get billing platform metrics: {e}")
|
|
return []
|
|
|
|
def get_merchant_metrics(
|
|
self,
|
|
db: Session,
|
|
merchant_id: int,
|
|
context: MetricsContext | None = None,
|
|
) -> list[MetricValue]:
|
|
"""
|
|
Get subscription metrics for a specific merchant.
|
|
|
|
Provides:
|
|
- Active subscriptions (active + trial)
|
|
"""
|
|
from app.modules.billing.models import MerchantSubscription
|
|
|
|
try:
|
|
active_subs = (
|
|
db.query(func.count(MerchantSubscription.id))
|
|
.filter(
|
|
MerchantSubscription.merchant_id == merchant_id,
|
|
MerchantSubscription.status.in_(["active", "trial"]),
|
|
)
|
|
.scalar()
|
|
or 0
|
|
)
|
|
|
|
return [
|
|
MetricValue(
|
|
key="billing.active_subscriptions",
|
|
value=active_subs,
|
|
label="Active Subscriptions",
|
|
category="billing",
|
|
icon="clipboard-list",
|
|
description="Active or trial subscriptions for this merchant",
|
|
),
|
|
]
|
|
except Exception as e:
|
|
logger.warning(f"Failed to get billing merchant metrics: {e}")
|
|
return []
|
|
|
|
|
|
# Singleton instance
|
|
billing_metrics_provider = BillingMetricsProvider()
|
|
|
|
__all__ = ["BillingMetricsProvider", "billing_metrics_provider"]
|