feat(loyalty): fix Google Wallet integration and improve enrollment flow
- Fix Google Wallet class creation: add required issuerName field (merchant name), programLogo with default logo fallback, hexBackgroundColor default - Add default loyalty logo assets (200px + 512px) for programs without custom logos - Smart retry: skip retries on 400/401/403/404 client errors (not transient) - Fix enrollment success page: use sessionStorage for wallet URLs instead of authenticated API call (self-enrolled customers have no session) - Hide wallet section on success page when no wallet URLs available - Wire up T&C modal on enrollment page with program.terms_text - Add startup validation for Google/Apple Wallet configs in lifespan - Add admin wallet status dashboard endpoint and UI (moved to service layer) - Fix Apple Wallet push notifications with real APNs HTTP/2 implementation - Fix docs: correct enrollment URLs (port, path segments, /v1 prefix) - Fix test assertion: !loyalty-enroll! → !enrollment! Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -222,6 +222,17 @@ class Settings(BaseSettings):
|
||||
# =============================================================================
|
||||
loyalty_google_issuer_id: str | None = None
|
||||
loyalty_google_service_account_json: str | None = None # Path to service account JSON
|
||||
loyalty_google_wallet_origins: list[str] = [] # Allowed origins for save-to-wallet JWT
|
||||
loyalty_default_logo_url: str = "https://rewardflow.lu/static/modules/loyalty/shared/img/default-logo-200.png"
|
||||
|
||||
# =============================================================================
|
||||
# APPLE WALLET (LOYALTY MODULE)
|
||||
# =============================================================================
|
||||
loyalty_apple_pass_type_id: str | None = None
|
||||
loyalty_apple_team_id: str | None = None
|
||||
loyalty_apple_wwdr_cert_path: str | None = None
|
||||
loyalty_apple_signer_cert_path: str | None = None
|
||||
loyalty_apple_signer_key_path: str | None = None
|
||||
|
||||
model_config = {"env_file": ".env"}
|
||||
|
||||
|
||||
@@ -44,6 +44,9 @@ async def lifespan(app: FastAPI):
|
||||
grafana_url=settings.grafana_url,
|
||||
)
|
||||
|
||||
# Validate wallet configurations
|
||||
_validate_wallet_config()
|
||||
|
||||
logger.info("[OK] Application startup completed")
|
||||
|
||||
yield
|
||||
@@ -53,6 +56,72 @@ async def lifespan(app: FastAPI):
|
||||
shutdown_observability()
|
||||
|
||||
|
||||
def _validate_wallet_config():
|
||||
"""Validate Google/Apple Wallet configuration at startup."""
|
||||
try:
|
||||
from app.modules.loyalty.services.google_wallet_service import (
|
||||
google_wallet_service,
|
||||
)
|
||||
|
||||
result = google_wallet_service.validate_config()
|
||||
if result["configured"]:
|
||||
if result["credentials_valid"]:
|
||||
logger.info(
|
||||
"[OK] Google Wallet configured (issuer: %s, email: %s)",
|
||||
result["issuer_id"],
|
||||
result.get("service_account_email", "unknown"),
|
||||
)
|
||||
else:
|
||||
for err in result["errors"]:
|
||||
logger.error("[FAIL] Google Wallet config error: %s", err)
|
||||
else:
|
||||
logger.info("[--] Google Wallet not configured (optional)")
|
||||
|
||||
# Apple Wallet config check
|
||||
if settings.loyalty_apple_pass_type_id:
|
||||
import os
|
||||
|
||||
missing = []
|
||||
for field in [
|
||||
"loyalty_apple_team_id",
|
||||
"loyalty_apple_wwdr_cert_path",
|
||||
"loyalty_apple_signer_cert_path",
|
||||
"loyalty_apple_signer_key_path",
|
||||
]:
|
||||
val = getattr(settings, field, None)
|
||||
if not val:
|
||||
missing.append(field)
|
||||
elif field.endswith("_path") and not os.path.isfile(val):
|
||||
logger.error(
|
||||
"[FAIL] Apple Wallet file not found: %s = %s",
|
||||
field,
|
||||
val,
|
||||
)
|
||||
|
||||
if missing:
|
||||
logger.error(
|
||||
"[FAIL] Apple Wallet missing config: %s",
|
||||
", ".join(missing),
|
||||
)
|
||||
elif not any(
|
||||
not os.path.isfile(getattr(settings, f, "") or "")
|
||||
for f in [
|
||||
"loyalty_apple_wwdr_cert_path",
|
||||
"loyalty_apple_signer_cert_path",
|
||||
"loyalty_apple_signer_key_path",
|
||||
]
|
||||
):
|
||||
logger.info(
|
||||
"[OK] Apple Wallet configured (pass type: %s)",
|
||||
settings.loyalty_apple_pass_type_id,
|
||||
)
|
||||
else:
|
||||
logger.info("[--] Apple Wallet not configured (optional)")
|
||||
|
||||
except Exception as exc: # noqa: BLE001
|
||||
logger.warning("Wallet config validation skipped: %s", exc)
|
||||
|
||||
|
||||
# === NEW HELPER FUNCTION ===
|
||||
def check_database_ready():
|
||||
"""Check if database is ready (migrations have been run)."""
|
||||
|
||||
Reference in New Issue
Block a user