Files
orion/app/modules/loyalty/definition.py
Samir Boulahtit 967f08e4ba feat: add module definition completeness validation and permissions
Add new validation rules MOD-020 to MOD-023 for module definition
completeness and standardize permissions across all modules.

Changes:
- Add MOD-020: Module definitions must have required attributes
- Add MOD-021: Modules with menus should have features
- Add MOD-022: Feature modules should have permissions
- Add MOD-023: Modules with routers should use get_*_with_routers pattern

Module permissions added:
- analytics: view, export, manage_dashboards
- billing: view_tiers, manage_tiers, view_subscriptions, manage_subscriptions, view_invoices
- cart: view, manage
- checkout: view_settings, manage_settings
- cms: view_pages, manage_pages, view_media, manage_media, manage_themes
- loyalty: view_programs, manage_programs, view_rewards, manage_rewards
- marketplace: view_integration, manage_integration, sync_products
- messaging: view_messages, send_messages, manage_templates
- payments: view_gateways, manage_gateways, view_transactions

Module improvements:
- Complete cart module with features and permissions
- Complete checkout module with features and permissions
- Add features to catalog module
- Add version to cms module
- Fix loyalty platform_router attachment
- Add path definitions to payments module
- Remove empty scheduled_tasks from dev_tools module

Documentation:
- Update module-system.md with new validation rules
- Update architecture-rules.md with MOD-020 to MOD-023

Tests:
- Add unit tests for module definition completeness
- Add tests for permission structure validation

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-02 18:23:04 +01:00

203 lines
7.2 KiB
Python

# app/modules/loyalty/definition.py
"""
Loyalty module definition.
Defines the loyalty module including its features, menu items,
route configurations, and scheduled tasks.
"""
from app.modules.base import MenuItemDefinition, MenuSectionDefinition, ModuleDefinition, PermissionDefinition, ScheduledTask
from app.modules.enums import FrontendType
def _get_admin_router():
"""Lazy import of admin router to avoid circular imports."""
from app.modules.loyalty.routes.api.admin import admin_router
return admin_router
def _get_vendor_router():
"""Lazy import of vendor router to avoid circular imports."""
from app.modules.loyalty.routes.api.vendor import vendor_router
return vendor_router
def _get_platform_router():
"""Lazy import of platform router to avoid circular imports."""
from app.modules.loyalty.routes.api.platform import platform_router
return platform_router
# Loyalty module definition
loyalty_module = ModuleDefinition(
code="loyalty",
name="Loyalty Programs",
description=(
"Stamp-based and points-based loyalty programs with Google Wallet "
"and Apple Wallet integration. Includes anti-fraud features like "
"staff PINs, cooldown periods, and daily limits."
),
version="1.0.0",
requires=["customers"], # Depends on customers module for customer data
features=[
# Core features
"loyalty_stamps", # Stamp-based loyalty
"loyalty_points", # Points-based loyalty
"loyalty_hybrid", # Both stamps and points
# Card management
"loyalty_cards", # Customer card management
"loyalty_enrollment", # Customer enrollment
# Staff/fraud prevention
"loyalty_staff_pins", # Staff PIN management
"loyalty_anti_fraud", # Cooldown, daily limits
# Wallet integration
"loyalty_google_wallet", # Google Wallet passes
"loyalty_apple_wallet", # Apple Wallet passes
# Analytics
"loyalty_stats", # Dashboard statistics
"loyalty_reports", # Transaction reports
],
# Module-driven permissions
permissions=[
PermissionDefinition(
id="loyalty.view_programs",
label_key="loyalty.permissions.view_programs",
description_key="loyalty.permissions.view_programs_desc",
category="loyalty",
),
PermissionDefinition(
id="loyalty.manage_programs",
label_key="loyalty.permissions.manage_programs",
description_key="loyalty.permissions.manage_programs_desc",
category="loyalty",
),
PermissionDefinition(
id="loyalty.view_rewards",
label_key="loyalty.permissions.view_rewards",
description_key="loyalty.permissions.view_rewards_desc",
category="loyalty",
),
PermissionDefinition(
id="loyalty.manage_rewards",
label_key="loyalty.permissions.manage_rewards",
description_key="loyalty.permissions.manage_rewards_desc",
category="loyalty",
),
],
menu_items={
FrontendType.ADMIN: [
"loyalty-programs", # View all programs
"loyalty-analytics", # Platform-wide stats
],
FrontendType.VENDOR: [
"loyalty", # Loyalty dashboard
"loyalty-cards", # Customer cards
"loyalty-stats", # Vendor stats
],
},
# New module-driven menu definitions
menus={
FrontendType.ADMIN: [
MenuSectionDefinition(
id="loyalty",
label_key="loyalty.menu.loyalty",
icon="gift",
order=55,
items=[
MenuItemDefinition(
id="loyalty-programs",
label_key="loyalty.menu.programs",
icon="gift",
route="/admin/loyalty/programs",
order=10,
),
MenuItemDefinition(
id="loyalty-analytics",
label_key="loyalty.menu.analytics",
icon="chart-bar",
route="/admin/loyalty/analytics",
order=20,
),
],
),
],
FrontendType.VENDOR: [
MenuSectionDefinition(
id="loyalty",
label_key="loyalty.menu.loyalty_programs",
icon="gift",
order=35,
items=[
MenuItemDefinition(
id="loyalty",
label_key="loyalty.menu.dashboard",
icon="gift",
route="/vendor/{vendor_code}/loyalty",
order=10,
),
MenuItemDefinition(
id="loyalty-cards",
label_key="loyalty.menu.customer_cards",
icon="identification",
route="/vendor/{vendor_code}/loyalty/cards",
order=20,
),
MenuItemDefinition(
id="loyalty-stats",
label_key="loyalty.menu.statistics",
icon="chart-bar",
route="/vendor/{vendor_code}/loyalty/stats",
order=30,
),
],
),
],
},
is_core=False, # Loyalty can be disabled
# =========================================================================
# Self-Contained Module Configuration
# =========================================================================
is_self_contained=True,
services_path="app.modules.loyalty.services",
models_path="app.modules.loyalty.models",
schemas_path="app.modules.loyalty.schemas",
exceptions_path="app.modules.loyalty.exceptions",
tasks_path="app.modules.loyalty.tasks",
# =========================================================================
# Scheduled Tasks
# =========================================================================
scheduled_tasks=[
ScheduledTask(
name="loyalty.sync_wallet_passes",
task="app.modules.loyalty.tasks.wallet_sync.sync_wallet_passes",
schedule="0 * * * *", # Hourly
options={"queue": "scheduled"},
),
ScheduledTask(
name="loyalty.expire_points",
task="app.modules.loyalty.tasks.point_expiration.expire_points",
schedule="0 2 * * *", # Daily at 02:00
options={"queue": "scheduled"},
),
],
)
def get_loyalty_module_with_routers() -> ModuleDefinition:
"""
Get loyalty module with routers attached.
This function attaches the routers lazily to avoid circular imports
during module initialization.
"""
loyalty_module.admin_router = _get_admin_router()
loyalty_module.vendor_router = _get_vendor_router()
loyalty_module.platform_router = _get_platform_router()
return loyalty_module
__all__ = ["loyalty_module", "get_loyalty_module_with_routers"]