feat(loyalty): refactor analytics into shared template and add merchant stats API
Some checks failed
CI / ruff (push) Successful in 11s
CI / validate (push) Has been cancelled
CI / dependency-scanning (push) Has been cancelled
CI / docs (push) Has been cancelled
CI / deploy (push) Has been cancelled
CI / pytest (push) Has been cancelled

Extract analytics stat cards, points activity, and location breakdown
into a shared partial used by admin, merchant, and store dashboards.
Add merchant stats API endpoint and client-side merchant filter on admin
analytics page. Extend stats schema with new_this_month and
estimated_liability_cents fields.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-03-11 11:08:16 +01:00
parent 8cf5da6914
commit 6acd783754
11 changed files with 630 additions and 375 deletions

View File

@@ -28,6 +28,7 @@ from app.modules.loyalty.schemas import (
ProgramResponse,
ProgramUpdate,
)
from app.modules.loyalty.schemas.program import MerchantStatsResponse
from app.modules.loyalty.services import program_service
from app.modules.tenancy.models import Merchant
@@ -49,6 +50,21 @@ def _build_program_response(program) -> ProgramResponse:
return response
# =============================================================================
# Statistics
# =============================================================================
@router.get("/stats", response_model=MerchantStatsResponse)
def get_stats(
merchant: Merchant = Depends(get_merchant_for_current_user),
db: Session = Depends(get_db),
):
"""Get merchant-wide loyalty statistics across all locations."""
stats = program_service.get_merchant_stats(db, merchant.id)
return MerchantStatsResponse(**stats)
# =============================================================================
# Program CRUD
# =============================================================================

View File

@@ -145,24 +145,13 @@ async def merchant_loyalty_analytics(
"""
Render merchant loyalty analytics page.
Shows aggregate loyalty program stats across all merchant stores.
Stats are loaded client-side via JS fetch.
"""
merchant_id = merchant.id
stats = {}
try:
stats = program_service.get_merchant_stats(db, merchant_id)
except Exception:
logger.warning(
f"Failed to load loyalty stats for merchant {merchant_id}",
exc_info=True,
)
context = _get_merchant_context(
request,
db,
current_user,
loyalty_stats=stats,
merchant_id=merchant_id,
merchant_id=merchant.id,
)
return templates.TemplateResponse(
"loyalty/merchant/analytics.html",