feat: add SQL query tool, platform debug, loyalty settings, and multi-module improvements
Some checks failed
Some checks failed
- Add admin SQL query tool with saved queries, schema explorer presets, and collapsible category sections (dev_tools module) - Add platform debug tool for admin diagnostics - Add loyalty settings page with owner-only access control - Fix loyalty settings owner check (use currentUser instead of window.__userData) - Replace HTTPException with AuthorizationException in loyalty routes - Expand loyalty module with PIN service, Apple Wallet, program management - Improve store login with platform detection and multi-platform support - Update billing feature gates and subscription services - Add store platform sync improvements and remove is_primary column - Add unit tests for loyalty (PIN, points, stamps, program services) - Update i18n translations across dev_tools locales Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -115,8 +115,9 @@ class MerchantDomainService:
|
||||
db.query(StorePlatform)
|
||||
.filter(
|
||||
StorePlatform.store_id.in_(store_ids),
|
||||
StorePlatform.is_primary.is_(True),
|
||||
StorePlatform.is_active == True, # noqa: E712
|
||||
)
|
||||
.order_by(StorePlatform.joined_at)
|
||||
.first()
|
||||
)
|
||||
platform_id = primary_sp.platform_id if primary_sp else None
|
||||
|
||||
@@ -324,9 +324,12 @@ class PlatformService:
|
||||
# ========================================================================
|
||||
|
||||
@staticmethod
|
||||
def get_primary_platform_id_for_store(db: Session, store_id: int) -> int | None:
|
||||
def get_first_active_platform_id_for_store(db: Session, store_id: int) -> int | None:
|
||||
"""
|
||||
Get the primary platform ID for a store.
|
||||
Get the first active platform ID for a store (ordered by joined_at).
|
||||
|
||||
Used as a fallback when platform_id is not available from JWT context
|
||||
(e.g. background tasks, old tokens).
|
||||
|
||||
Args:
|
||||
db: Database session
|
||||
@@ -341,7 +344,7 @@ class PlatformService:
|
||||
StorePlatform.store_id == store_id,
|
||||
StorePlatform.is_active == True, # noqa: E712
|
||||
)
|
||||
.order_by(StorePlatform.is_primary.desc())
|
||||
.order_by(StorePlatform.joined_at)
|
||||
.first()
|
||||
)
|
||||
return result[0] if result else None
|
||||
@@ -364,7 +367,7 @@ class PlatformService:
|
||||
StorePlatform.store_id == store_id,
|
||||
StorePlatform.is_active == True, # noqa: E712
|
||||
)
|
||||
.order_by(StorePlatform.is_primary.desc())
|
||||
.order_by(StorePlatform.joined_at)
|
||||
.all()
|
||||
)
|
||||
return [r[0] for r in results]
|
||||
@@ -393,29 +396,6 @@ class PlatformService:
|
||||
.first()
|
||||
)
|
||||
|
||||
@staticmethod
|
||||
def get_primary_store_platform_entry(
|
||||
db: Session, store_id: int
|
||||
) -> StorePlatform | None:
|
||||
"""
|
||||
Get the primary StorePlatform entry for a store.
|
||||
|
||||
Args:
|
||||
db: Database session
|
||||
store_id: Store ID
|
||||
|
||||
Returns:
|
||||
StorePlatform object or None
|
||||
"""
|
||||
return (
|
||||
db.query(StorePlatform)
|
||||
.filter(
|
||||
StorePlatform.store_id == store_id,
|
||||
StorePlatform.is_primary.is_(True),
|
||||
)
|
||||
.first()
|
||||
)
|
||||
|
||||
@staticmethod
|
||||
def get_store_ids_for_platform(
|
||||
db: Session, platform_id: int, active_only: bool = True
|
||||
@@ -450,7 +430,7 @@ class PlatformService:
|
||||
Upsert a StorePlatform entry.
|
||||
|
||||
If the entry exists, update is_active (and tier_id if provided).
|
||||
If missing and is_active=True, create it (set is_primary if store has none).
|
||||
If missing and is_active=True, create it.
|
||||
If missing and is_active=False, no-op.
|
||||
|
||||
Args:
|
||||
@@ -479,20 +459,10 @@ class PlatformService:
|
||||
return existing
|
||||
|
||||
if is_active:
|
||||
has_primary = (
|
||||
db.query(StorePlatform)
|
||||
.filter(
|
||||
StorePlatform.store_id == store_id,
|
||||
StorePlatform.is_primary.is_(True),
|
||||
)
|
||||
.first()
|
||||
) is not None
|
||||
|
||||
sp = StorePlatform(
|
||||
store_id=store_id,
|
||||
platform_id=platform_id,
|
||||
is_active=True,
|
||||
is_primary=not has_primary,
|
||||
tier_id=tier_id,
|
||||
)
|
||||
db.add(sp)
|
||||
|
||||
@@ -105,16 +105,13 @@ class StoreDomainService:
|
||||
if domain_data.is_primary:
|
||||
self._unset_primary_domains(db, store_id)
|
||||
|
||||
# Resolve platform_id: use provided value, or auto-resolve from primary StorePlatform
|
||||
# Resolve platform_id: use provided value, or auto-resolve from first active StorePlatform
|
||||
platform_id = domain_data.platform_id
|
||||
if not platform_id:
|
||||
from app.modules.tenancy.models import StorePlatform
|
||||
primary_sp = (
|
||||
db.query(StorePlatform)
|
||||
.filter(StorePlatform.store_id == store_id, StorePlatform.is_primary.is_(True))
|
||||
.first()
|
||||
from app.modules.tenancy.services.platform_service import (
|
||||
platform_service,
|
||||
)
|
||||
platform_id = primary_sp.platform_id if primary_sp else None
|
||||
platform_id = platform_service.get_first_active_platform_id_for_store(db, store_id)
|
||||
|
||||
# Create domain record
|
||||
new_domain = StoreDomain(
|
||||
|
||||
Reference in New Issue
Block a user