diff --git a/CLAUDE.md b/CLAUDE.md index 27be45f..a37da0b 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -62,25 +62,51 @@ docker compose -f docker-compose.local.yml exec django python manage.py 1=multilane, 0=unlimited) - `saved_lane_count` - remembers lane count when multilane disabled - `buffer_duration` - time between events -### Event (schedule/models.py) +### Event (scheduling/schedule/models.py) - `title`, `start_time`, `end_time`, `status` - Links to resources/customers via `Participant` model -### User (users/models.py) +### User (identity/users/models.py) - Roles: `superuser`, `platform_manager`, `platform_support`, `owner`, `manager`, `staff`, `resource`, `customer` - `business_subdomain` - which tenant they belong to + +### Tenant (identity/core/models.py) +- `name`, `subdomain`, `schema_name` +- Multi-tenancy via django-tenants diff --git a/smoothschedule/SETUP_GUIDE.md b/smoothschedule/SETUP_GUIDE.md index bcea42c..13ce82c 100644 --- a/smoothschedule/SETUP_GUIDE.md +++ b/smoothschedule/SETUP_GUIDE.md @@ -159,7 +159,7 @@ docker-compose -f docker-compose.local.yml run --rm django python manage.py migr In Django shell or admin, create users with different roles: ```python -from smoothschedule.users.models import User +from smoothschedule.identity.users.models import User from core.models import Tenant # Get the tenant diff --git a/smoothschedule/config/api_router.py b/smoothschedule/config/api_router.py index 8f7a988..c73ade9 100644 --- a/smoothschedule/config/api_router.py +++ b/smoothschedule/config/api_router.py @@ -2,7 +2,7 @@ from django.conf import settings from rest_framework.routers import DefaultRouter from rest_framework.routers import SimpleRouter -from smoothschedule.users.api.views import UserViewSet +from smoothschedule.identity.users.api.views import UserViewSet router = DefaultRouter() if settings.DEBUG else SimpleRouter() diff --git a/smoothschedule/config/asgi.py b/smoothschedule/config/asgi.py index f4e2aff..b862f9a 100644 --- a/smoothschedule/config/asgi.py +++ b/smoothschedule/config/asgi.py @@ -10,9 +10,9 @@ django_asgi_app = get_asgi_application() from channels.auth import AuthMiddlewareStack from channels.routing import ProtocolTypeRouter, URLRouter -from tickets import routing as tickets_routing -from schedule import routing as schedule_routing -from tickets.middleware import TokenAuthMiddleware +from smoothschedule.commerce.tickets import routing as tickets_routing +from smoothschedule.scheduling.schedule import routing as schedule_routing +from smoothschedule.commerce.tickets.middleware import TokenAuthMiddleware application = ProtocolTypeRouter( diff --git a/smoothschedule/config/settings/base.py b/smoothschedule/config/settings/base.py index b93eeba..1194670 100644 --- a/smoothschedule/config/settings/base.py +++ b/smoothschedule/config/settings/base.py @@ -97,17 +97,28 @@ THIRD_PARTY_APPS = [ ] LOCAL_APPS = [ - "smoothschedule.users", - "core", - "schedule", - "analytics", - "payments", - "platform_admin.apps.PlatformAdminConfig", - "notifications", # New: Generic notification app - "tickets", # New: Support tickets app - "smoothschedule.comms_credits", # Communication credits and SMS/calling - "smoothschedule.field_mobile", # Field employee mobile app - # Your stuff: custom apps go here + # Identity Domain + "smoothschedule.identity.users", + "smoothschedule.identity.core", + + # Scheduling Domain + "smoothschedule.scheduling.schedule", + "smoothschedule.scheduling.contracts", + "smoothschedule.scheduling.analytics", + + # Communication Domain + "smoothschedule.communication.notifications", + "smoothschedule.communication.credits", # SMS/calling credits (was comms_credits) + "smoothschedule.communication.mobile", # Field employee app (was field_mobile) + "smoothschedule.communication.messaging", # Twilio conversations (was communication) + + # Commerce Domain + "smoothschedule.commerce.payments", + "smoothschedule.commerce.tickets", + + # Platform Domain + "smoothschedule.platform.admin", # Platform settings (was platform_admin) + "smoothschedule.platform.api", # Public API v1 (was public_api) ] # https://docs.djangoproject.com/en/dev/ref/settings/#installed-apps INSTALLED_APPS = DJANGO_APPS + THIRD_PARTY_APPS + LOCAL_APPS @@ -183,7 +194,7 @@ TEMPLATES = [ "django.template.context_processors.media", "django.template.context_processors.static", "django.template.context_processors.tz", - "smoothschedule.users.context_processors.allauth_settings", + "smoothschedule.identity.users.context_processors.allauth_settings", ], }, }, @@ -318,13 +329,13 @@ ACCOUNT_SIGNUP_FIELDS = ["email*", "username*", "password1*", "password2*"] # https://docs.allauth.org/en/latest/account/configuration.html ACCOUNT_EMAIL_VERIFICATION = "mandatory" # https://docs.allauth.org/en/latest/account/configuration.html -ACCOUNT_ADAPTER = "smoothschedule.users.adapters.AccountAdapter" +ACCOUNT_ADAPTER = "smoothschedule.identity.users.adapters.AccountAdapter" # https://docs.allauth.org/en/latest/account/forms.html -ACCOUNT_FORMS = {"signup": "smoothschedule.users.forms.UserSignupForm"} +ACCOUNT_FORMS = {"signup": "smoothschedule.identity.users.forms.UserSignupForm"} # https://docs.allauth.org/en/latest/socialaccount/configuration.html -SOCIALACCOUNT_ADAPTER = "smoothschedule.users.adapters.SocialAccountAdapter" +SOCIALACCOUNT_ADAPTER = "smoothschedule.identity.users.adapters.SocialAccountAdapter" # https://docs.allauth.org/en/latest/socialaccount/configuration.html -SOCIALACCOUNT_FORMS = {"signup": "smoothschedule.users.forms.UserSocialSignupForm"} +SOCIALACCOUNT_FORMS = {"signup": "smoothschedule.identity.users.forms.UserSocialSignupForm"} # django-rest-framework # ------------------------------------------------------------------------------- diff --git a/smoothschedule/config/settings/multitenancy.py b/smoothschedule/config/settings/multitenancy.py index 8a0b9be..ee2fced 100644 --- a/smoothschedule/config/settings/multitenancy.py +++ b/smoothschedule/config/settings/multitenancy.py @@ -13,10 +13,16 @@ from .base import INSTALLED_APPS, MIDDLEWARE, DATABASES, LOGGING, env # Shared apps - Available to all tenants (stored in 'public' schema) SHARED_APPS = [ 'django_tenants', # Must be first - 'core', # Core models (Tenant, Domain, PermissionGrant) - 'platform_admin.apps.PlatformAdminConfig', # Platform management (TenantInvitation, etc.) - # Django built-ins (must be in shared + # Identity Domain (shared) + 'smoothschedule.identity.core', # Core models (Tenant, Domain, PermissionGrant) + 'smoothschedule.identity.users', # Users app (shared across tenants) + + # Platform Domain (shared) + 'smoothschedule.platform.admin', # Platform management (TenantInvitation, etc.) + 'smoothschedule.platform.api', # Public API v1 for third-party integrations + + # Django built-ins (must be in shared) 'django.contrib.contenttypes', 'django.contrib.auth', 'django.contrib.sessions', @@ -25,15 +31,12 @@ SHARED_APPS = [ 'django.contrib.staticfiles', 'django.contrib.admin', - # Users app (shared across tenants) - 'smoothschedule.users', - # Third-party apps that should be shared 'rest_framework', 'rest_framework.authtoken', 'corsheaders', 'drf_spectacular', - 'channels', # WebSockets + 'channels', # WebSockets 'allauth', 'allauth.account', 'allauth.mfa', @@ -45,23 +48,26 @@ SHARED_APPS = [ 'crispy_bootstrap5', 'csp', 'djstripe', # Stripe integration - 'tickets', # Ticket system - shared for platform support access - 'notifications', # Notification system - shared for platform to notify tenants - 'smoothschedule.public_api', # Public API v1 for third-party integrations - 'smoothschedule.comms_credits', # Communication credits (SMS/calling) - shared for billing - 'smoothschedule.field_mobile', # Field employee mobile app - shared for location tracking + + # Commerce Domain (shared for platform support) + 'smoothschedule.commerce.tickets', # Ticket system - shared for platform support access + + # Communication Domain (shared) + 'smoothschedule.communication.notifications', # Notification system - shared for platform + 'smoothschedule.communication.credits', # Communication credits (SMS/calling) - shared for billing + 'smoothschedule.communication.mobile', # Field employee mobile app - shared for location tracking ] # Tenant-specific apps - Each tenant gets isolated data in their own schema TENANT_APPS = [ 'django.contrib.contenttypes', # Needed for tenant schemas - 'schedule', # Resource scheduling with configurable concurrency - 'payments', # Stripe Connect payments bridge - 'contracts', # Contract/e-signature system - # Add your tenant-scoped business logic apps here: - # 'appointments', - # 'customers', - # 'analytics', + + # Scheduling Domain (tenant-isolated) + 'smoothschedule.scheduling.schedule', # Resource scheduling with configurable concurrency + 'smoothschedule.scheduling.contracts', # Contract/e-signature system + + # Commerce Domain (tenant-isolated) + 'smoothschedule.commerce.payments', # Stripe Connect payments bridge ] @@ -96,7 +102,7 @@ MIDDLEWARE = [ # 1. Tenant resolution 'django_tenants.middleware.main.TenantMainMiddleware', - 'core.middleware.TenantHeaderMiddleware', # Support tenant switching via header + 'smoothschedule.identity.core.middleware.TenantHeaderMiddleware', # Support tenant switching via header # 2. Security middleware 'django.middleware.security.SecurityMiddleware', @@ -108,7 +114,7 @@ MIDDLEWARE = [ # 4. Sandbox mode - switches to sandbox schema if requested # MUST come after TenantMainMiddleware and SessionMiddleware - 'core.middleware.SandboxModeMiddleware', + 'smoothschedule.identity.core.middleware.SandboxModeMiddleware', 'django.middleware.locale.LocaleMiddleware', 'django.middleware.common.CommonMiddleware', 'django.middleware.csrf.CsrfViewMiddleware', @@ -120,7 +126,7 @@ MIDDLEWARE = [ 'hijack.middleware.HijackUserMiddleware', # 6. MASQUERADE AUDIT - MUST come AFTER HijackUserMiddleware - 'core.middleware.MasqueradeAuditMiddleware', + 'smoothschedule.identity.core.middleware.MasqueradeAuditMiddleware', # 7. Messages, Clickjacking, and Allauth 'django.contrib.messages.middleware.MessageMiddleware', @@ -176,7 +182,7 @@ AUTH_PASSWORD_VALIDATORS = [ # HIJACK (MASQUERADING) CONFIGURATION # ============================================================================= -HIJACK_AUTHORIZATION_CHECK = 'core.permissions.can_hijack' +HIJACK_AUTHORIZATION_CHECK = 'smoothschedule.identity.core.permissions.can_hijack' HIJACK_DISPLAY_ADMIN_BUTTON = True HIJACK_USE_BOOTSTRAP = True HIJACK_ALLOW_GET_REQUESTS = False # Security: require POST diff --git a/smoothschedule/config/settings/test.py b/smoothschedule/config/settings/test.py index a243c98..c5fa983 100644 --- a/smoothschedule/config/settings/test.py +++ b/smoothschedule/config/settings/test.py @@ -2,9 +2,8 @@ With these settings, tests run faster. """ -from .base import * # noqa: F403 -from .base import TEMPLATES -from .base import env +from .multitenancy import * # noqa: F403 +from .multitenancy import TEMPLATES, env # GENERAL # ------------------------------------------------------------------------------ diff --git a/smoothschedule/config/urls.py b/smoothschedule/config/urls.py index a4863e9..636205a 100644 --- a/smoothschedule/config/urls.py +++ b/smoothschedule/config/urls.py @@ -10,33 +10,33 @@ from drf_spectacular.views import SpectacularAPIView from drf_spectacular.views import SpectacularSwaggerView from rest_framework.authtoken.views import obtain_auth_token -from smoothschedule.users.api_views import ( +from smoothschedule.identity.users.api_views import ( login_view, current_user_view, logout_view, send_verification_email, verify_email, hijack_acquire_view, hijack_release_view, staff_invitations_view, cancel_invitation_view, resend_invitation_view, invitation_details_view, accept_invitation_view, decline_invitation_view, check_subdomain_view, signup_view ) -from smoothschedule.users.mfa_api_views import ( +from smoothschedule.identity.users.mfa_api_views import ( mfa_status, send_phone_verification, verify_phone, enable_sms_mfa, setup_totp, verify_totp_setup, generate_backup_codes, backup_codes_status, disable_mfa, mfa_login_send_code, mfa_login_verify, list_trusted_devices, revoke_trusted_device, revoke_all_trusted_devices ) -from schedule.api_views import ( +from smoothschedule.scheduling.schedule.api_views import ( current_business_view, update_business_view, oauth_settings_view, oauth_credentials_view, custom_domains_view, custom_domain_detail_view, custom_domain_verify_view, custom_domain_set_primary_view, sandbox_status_view, sandbox_toggle_view, sandbox_reset_view ) -from core.email_autoconfig import ( +from smoothschedule.identity.core.email_autoconfig import ( MozillaAutoconfigView, MicrosoftAutodiscoverView, AppleConfigProfileView, WellKnownAutoconfigView, ) -from core.api_views import ( +from smoothschedule.identity.core.api_views import ( quota_status_view, quota_resources_view, quota_archive_view, @@ -48,7 +48,7 @@ urlpatterns = [ # Django Admin, use {% url 'admin:index' %} path(settings.ADMIN_URL, admin.site.urls), # User management - path("users/", include("smoothschedule.users.urls", namespace="users")), + path("users/", include("smoothschedule.identity.users.urls", namespace="users")), path("accounts/", include("allauth.urls")), # Django Hijack (masquerade) - for admin interface path("hijack/", include("hijack.urls")), @@ -78,28 +78,28 @@ urlpatterns += [ # Stripe Webhooks (dj-stripe built-in handler) path("stripe/", include("djstripe.urls", namespace="djstripe")), # Public API v1 (for third-party integrations) - path("v1/", include("smoothschedule.public_api.urls", namespace="public_api")), + path("v1/", include("smoothschedule.platform.api.urls", namespace="public_api")), # Schedule API (internal) - path("", include("schedule.urls")), + path("", include("smoothschedule.scheduling.schedule.urls")), # Analytics API - path("", include("analytics.urls")), + path("", include("smoothschedule.scheduling.analytics.urls")), # Payments API - path("payments/", include("payments.urls")), + path("payments/", include("smoothschedule.commerce.payments.urls")), # Contracts API - path("contracts/", include("contracts.urls")), + path("contracts/", include("smoothschedule.scheduling.contracts.urls")), # Communication Credits API - path("communication-credits/", include("smoothschedule.comms_credits.urls", namespace="comms_credits")), + path("communication-credits/", include("smoothschedule.communication.credits.urls", namespace="comms_credits")), # Field Mobile API (for field employee mobile app) - path("mobile/", include("smoothschedule.field_mobile.urls", namespace="field_mobile")), + path("mobile/", include("smoothschedule.communication.mobile.urls", namespace="field_mobile")), # Tickets API - path("tickets/", include("tickets.urls")), + path("tickets/", include("smoothschedule.commerce.tickets.urls")), # Notifications API - path("notifications/", include("notifications.urls")), + path("notifications/", include("smoothschedule.communication.notifications.urls")), # Platform API - path("platform/", include("platform_admin.urls", namespace="platform")), + path("platform/", include("smoothschedule.platform.admin.urls", namespace="platform")), # OAuth Email Integration API - path("oauth/", include("core.oauth_urls", namespace="oauth")), - path("auth/oauth/", include("core.oauth_urls", namespace="auth_oauth")), + path("oauth/", include("smoothschedule.identity.core.oauth_urls", namespace="oauth")), + path("auth/oauth/", include("smoothschedule.identity.core.oauth_urls", namespace="auth_oauth")), # Auth API path("auth-token/", csrf_exempt(obtain_auth_token), name="obtain_auth_token"), path("auth/signup/check-subdomain/", check_subdomain_view, name="check_subdomain"), diff --git a/smoothschedule/create_admin.py b/smoothschedule/create_admin.py index 5259a3a..cb61299 100644 --- a/smoothschedule/create_admin.py +++ b/smoothschedule/create_admin.py @@ -6,7 +6,7 @@ import django os.environ.setdefault("DJANGO_SETTINGS_MODULE", "config.settings.local") django.setup() -from smoothschedule.users.models import User +from smoothschedule.identity.users.models import User from rest_framework.authtoken.models import Token # Create or get a superuser with platform admin role diff --git a/smoothschedule/create_default_tenant.py b/smoothschedule/create_default_tenant.py index 1b26d8f..659045f 100644 --- a/smoothschedule/create_default_tenant.py +++ b/smoothschedule/create_default_tenant.py @@ -1,7 +1,7 @@ """ Create a default tenant for local development """ -from core.models import Tenant, Domain +from smoothschedule.identity.core.models import Tenant, Domain from django.contrib.auth import get_user_model User = get_user_model() diff --git a/smoothschedule/debug_urls.py b/smoothschedule/debug_urls.py index 5733215..ccd694b 100644 --- a/smoothschedule/debug_urls.py +++ b/smoothschedule/debug_urls.py @@ -3,7 +3,7 @@ import os import django from django.conf import settings from django_tenants.utils import tenant_context -from core.models import Tenant +from smoothschedule.identity.core.models import Tenant # Setup Django os.environ.setdefault("DJANGO_SETTINGS_MODULE", "config.settings.local") diff --git a/smoothschedule/scripts/ensure_production_domain.py b/smoothschedule/scripts/ensure_production_domain.py index a8d3c28..69ad437 100644 --- a/smoothschedule/scripts/ensure_production_domain.py +++ b/smoothschedule/scripts/ensure_production_domain.py @@ -2,7 +2,7 @@ Script to ensure production domain exists in the database. Run with: python manage.py shell < scripts/ensure_production_domain.py """ -from core.models import Tenant, Domain +from smoothschedule.identity.core.models import Tenant, Domain from django.conf import settings def ensure_production_domain(): diff --git a/smoothschedule/analytics/__init__.py b/smoothschedule/smoothschedule/commerce/__init__.py similarity index 100% rename from smoothschedule/analytics/__init__.py rename to smoothschedule/smoothschedule/commerce/__init__.py diff --git a/smoothschedule/analytics/migrations/__init__.py b/smoothschedule/smoothschedule/commerce/payments/__init__.py similarity index 100% rename from smoothschedule/analytics/migrations/__init__.py rename to smoothschedule/smoothschedule/commerce/payments/__init__.py diff --git a/smoothschedule/communication/admin.py b/smoothschedule/smoothschedule/commerce/payments/admin.py similarity index 100% rename from smoothschedule/communication/admin.py rename to smoothschedule/smoothschedule/commerce/payments/admin.py diff --git a/smoothschedule/payments/apps.py b/smoothschedule/smoothschedule/commerce/payments/apps.py similarity index 64% rename from smoothschedule/payments/apps.py rename to smoothschedule/smoothschedule/commerce/payments/apps.py index 4886655..7fb6699 100644 --- a/smoothschedule/payments/apps.py +++ b/smoothschedule/smoothschedule/commerce/payments/apps.py @@ -3,4 +3,5 @@ from django.apps import AppConfig class PaymentsConfig(AppConfig): default_auto_field = 'django.db.models.BigAutoField' - name = 'payments' + name = 'smoothschedule.commerce.payments' + label = 'payments' diff --git a/smoothschedule/payments/migrations/0001_initial.py b/smoothschedule/smoothschedule/commerce/payments/migrations/0001_initial.py similarity index 100% rename from smoothschedule/payments/migrations/0001_initial.py rename to smoothschedule/smoothschedule/commerce/payments/migrations/0001_initial.py diff --git a/smoothschedule/communication/__init__.py b/smoothschedule/smoothschedule/commerce/payments/migrations/__init__.py similarity index 100% rename from smoothschedule/communication/__init__.py rename to smoothschedule/smoothschedule/commerce/payments/migrations/__init__.py diff --git a/smoothschedule/payments/models.py b/smoothschedule/smoothschedule/commerce/payments/models.py similarity index 99% rename from smoothschedule/payments/models.py rename to smoothschedule/smoothschedule/commerce/payments/models.py index 08a8e25..2f6f9b6 100644 --- a/smoothschedule/payments/models.py +++ b/smoothschedule/smoothschedule/commerce/payments/models.py @@ -92,6 +92,7 @@ class TransactionLink(models.Model): ) class Meta: + app_label = 'payments' ordering = ['-created_at'] indexes = [ models.Index(fields=['status', 'created_at']), diff --git a/smoothschedule/payments/services.py b/smoothschedule/smoothschedule/commerce/payments/services.py similarity index 100% rename from smoothschedule/payments/services.py rename to smoothschedule/smoothschedule/commerce/payments/services.py diff --git a/smoothschedule/communication/tests.py b/smoothschedule/smoothschedule/commerce/payments/tests.py similarity index 100% rename from smoothschedule/communication/tests.py rename to smoothschedule/smoothschedule/commerce/payments/tests.py diff --git a/smoothschedule/payments/urls.py b/smoothschedule/smoothschedule/commerce/payments/urls.py similarity index 100% rename from smoothschedule/payments/urls.py rename to smoothschedule/smoothschedule/commerce/payments/urls.py diff --git a/smoothschedule/payments/views.py b/smoothschedule/smoothschedule/commerce/payments/views.py similarity index 99% rename from smoothschedule/payments/views.py rename to smoothschedule/smoothschedule/commerce/payments/views.py index 40fb3c7..49ed2ae 100644 --- a/smoothschedule/payments/views.py +++ b/smoothschedule/smoothschedule/commerce/payments/views.py @@ -10,13 +10,13 @@ from rest_framework.views import APIView from rest_framework.response import Response from rest_framework.permissions import IsAuthenticated, AllowAny from rest_framework import status -from core.permissions import HasFeaturePermission -from core.mixins import TenantAPIView, TenantRequiredAPIView +from smoothschedule.identity.core.permissions import HasFeaturePermission +from smoothschedule.identity.core.mixins import TenantAPIView, TenantRequiredAPIView from decimal import Decimal from .services import get_stripe_service_for_tenant from .models import TransactionLink -from schedule.models import Event -from platform_admin.models import SubscriptionPlan +from smoothschedule.scheduling.schedule.models import Event +from smoothschedule.platform.admin.models import SubscriptionPlan # ============================================================================ @@ -1532,8 +1532,8 @@ class CustomerBillingView(APIView): def get(self, request): """Get customer billing data.""" from django.contrib.contenttypes.models import ContentType - from schedule.models import Participant - from smoothschedule.users.models import User + from smoothschedule.scheduling.schedule.models import Participant + from smoothschedule.identity.users.models import User user = request.user @@ -1653,7 +1653,7 @@ class CustomerPaymentMethodsView(APIView): def get(self, request): """Get customer's saved payment methods from Stripe.""" - from smoothschedule.users.models import User + from smoothschedule.identity.users.models import User user = request.user @@ -1726,7 +1726,7 @@ class CustomerSetupIntentView(APIView): """Create a SetupIntent for the customer.""" import logging logger = logging.getLogger(__name__) - from smoothschedule.users.models import User + from smoothschedule.identity.users.models import User user = request.user tenant = request.tenant @@ -1841,7 +1841,7 @@ class CustomerPaymentMethodDeleteView(APIView): def delete(self, request, payment_method_id): """Delete a payment method.""" - from smoothschedule.users.models import User + from smoothschedule.identity.users.models import User user = request.user @@ -1904,7 +1904,7 @@ class CustomerPaymentMethodDefaultView(APIView): def post(self, request, payment_method_id): """Set payment method as default.""" - from smoothschedule.users.models import User + from smoothschedule.identity.users.models import User user = request.user @@ -1989,8 +1989,8 @@ class SetFinalPriceView(APIView): import logging logger = logging.getLogger(__name__) from django.contrib.contenttypes.models import ContentType - from schedule.models import Participant - from smoothschedule.users.models import User + from smoothschedule.scheduling.schedule.models import Participant + from smoothschedule.identity.users.models import User final_price = request.data.get('final_price') charge_now = request.data.get('charge_now', True) diff --git a/smoothschedule/payments/webhooks.py b/smoothschedule/smoothschedule/commerce/payments/webhooks.py similarity index 98% rename from smoothschedule/payments/webhooks.py rename to smoothschedule/smoothschedule/commerce/payments/webhooks.py index 2e3f5f9..8d28dc2 100644 --- a/smoothschedule/payments/webhooks.py +++ b/smoothschedule/smoothschedule/commerce/payments/webhooks.py @@ -7,7 +7,7 @@ from django.dispatch import receiver from djstripe import signals from django.utils import timezone from .models import TransactionLink -from schedule.models import Event +from smoothschedule.scheduling.schedule.models import Event import logging logger = logging.getLogger(__name__) diff --git a/smoothschedule/communication/migrations/__init__.py b/smoothschedule/smoothschedule/commerce/tickets/__init__.py similarity index 100% rename from smoothschedule/communication/migrations/__init__.py rename to smoothschedule/smoothschedule/commerce/tickets/__init__.py diff --git a/smoothschedule/tickets/admin.py b/smoothschedule/smoothschedule/commerce/tickets/admin.py similarity index 100% rename from smoothschedule/tickets/admin.py rename to smoothschedule/smoothschedule/commerce/tickets/admin.py diff --git a/smoothschedule/tickets/apps.py b/smoothschedule/smoothschedule/commerce/tickets/apps.py similarity index 53% rename from smoothschedule/tickets/apps.py rename to smoothschedule/smoothschedule/commerce/tickets/apps.py index e83aab0..44b76d8 100644 --- a/smoothschedule/tickets/apps.py +++ b/smoothschedule/smoothschedule/commerce/tickets/apps.py @@ -3,7 +3,8 @@ from django.apps import AppConfig class TicketsConfig(AppConfig): default_auto_field = 'django.db.models.BigAutoField' - name = 'tickets' + name = 'smoothschedule.commerce.tickets' + label = 'tickets' def ready(self): - import tickets.signals # noqa + import smoothschedule.commerce.tickets.signals # noqa diff --git a/smoothschedule/tickets/consumers.py b/smoothschedule/smoothschedule/commerce/tickets/consumers.py similarity index 98% rename from smoothschedule/tickets/consumers.py rename to smoothschedule/smoothschedule/commerce/tickets/consumers.py index 73f0cb1..bec0b0c 100644 --- a/smoothschedule/tickets/consumers.py +++ b/smoothschedule/smoothschedule/commerce/tickets/consumers.py @@ -2,7 +2,7 @@ import json from channels.generic.websocket import AsyncWebsocketConsumer from asgiref.sync import sync_to_async -from smoothschedule.users.models import User +from smoothschedule.identity.users.models import User from .models import Ticket, TicketComment from .serializers import TicketSerializer, TicketCommentSerializer # Import your serializers diff --git a/smoothschedule/tickets/email_notifications.py b/smoothschedule/smoothschedule/commerce/tickets/email_notifications.py similarity index 99% rename from smoothschedule/tickets/email_notifications.py rename to smoothschedule/smoothschedule/commerce/tickets/email_notifications.py index 98fd033..d0f2d0e 100644 --- a/smoothschedule/tickets/email_notifications.py +++ b/smoothschedule/smoothschedule/commerce/tickets/email_notifications.py @@ -31,7 +31,7 @@ def get_default_platform_email(): Returns None if no default is configured. """ try: - from platform_admin.models import PlatformEmailAddress + from smoothschedule.platform.admin.models import PlatformEmailAddress return PlatformEmailAddress.objects.filter( is_default=True, is_active=True, @@ -75,7 +75,7 @@ class TicketEmailService: Returns None if template not found. """ try: - from schedule.models import EmailTemplate + from smoothschedule.scheduling.schedule.models import EmailTemplate return EmailTemplate.objects.filter( name=template_name, scope=EmailTemplate.Scope.BUSINESS diff --git a/smoothschedule/tickets/email_receiver.py b/smoothschedule/smoothschedule/commerce/tickets/email_receiver.py similarity index 99% rename from smoothschedule/tickets/email_receiver.py rename to smoothschedule/smoothschedule/commerce/tickets/email_receiver.py index ff93d7e..6a11129 100644 --- a/smoothschedule/tickets/email_receiver.py +++ b/smoothschedule/smoothschedule/commerce/tickets/email_receiver.py @@ -37,7 +37,7 @@ from .models import ( TicketEmailAddress, IncomingTicketEmail ) -from smoothschedule.users.models import User +from smoothschedule.identity.users.models import User logger = logging.getLogger(__name__) @@ -713,7 +713,7 @@ class PlatformEmailReceiver: def __init__(self, email_address): """Initialize with a PlatformEmailAddress instance.""" - from platform_admin.models import PlatformEmailAddress + from smoothschedule.platform.admin.models import PlatformEmailAddress self.email_address = email_address self.connection = None diff --git a/smoothschedule/contracts/__init__.py b/smoothschedule/smoothschedule/commerce/tickets/management/__init__.py similarity index 100% rename from smoothschedule/contracts/__init__.py rename to smoothschedule/smoothschedule/commerce/tickets/management/__init__.py diff --git a/smoothschedule/contracts/migrations/__init__.py b/smoothschedule/smoothschedule/commerce/tickets/management/commands/__init__.py similarity index 100% rename from smoothschedule/contracts/migrations/__init__.py rename to smoothschedule/smoothschedule/commerce/tickets/management/commands/__init__.py diff --git a/smoothschedule/tickets/management/commands/fetch_ticket_emails.py b/smoothschedule/smoothschedule/commerce/tickets/management/commands/fetch_ticket_emails.py similarity index 100% rename from smoothschedule/tickets/management/commands/fetch_ticket_emails.py rename to smoothschedule/smoothschedule/commerce/tickets/management/commands/fetch_ticket_emails.py diff --git a/smoothschedule/tickets/middleware.py b/smoothschedule/smoothschedule/commerce/tickets/middleware.py similarity index 100% rename from smoothschedule/tickets/middleware.py rename to smoothschedule/smoothschedule/commerce/tickets/middleware.py diff --git a/smoothschedule/tickets/migrations/0001_initial.py b/smoothschedule/smoothschedule/commerce/tickets/migrations/0001_initial.py similarity index 100% rename from smoothschedule/tickets/migrations/0001_initial.py rename to smoothschedule/smoothschedule/commerce/tickets/migrations/0001_initial.py diff --git a/smoothschedule/tickets/migrations/0002_cannedresponse_tickettemplate_ticket_due_at_and_more.py b/smoothschedule/smoothschedule/commerce/tickets/migrations/0002_cannedresponse_tickettemplate_ticket_due_at_and_more.py similarity index 100% rename from smoothschedule/tickets/migrations/0002_cannedresponse_tickettemplate_ticket_due_at_and_more.py rename to smoothschedule/smoothschedule/commerce/tickets/migrations/0002_cannedresponse_tickettemplate_ticket_due_at_and_more.py diff --git a/smoothschedule/tickets/migrations/0003_ticket_is_sandbox.py b/smoothschedule/smoothschedule/commerce/tickets/migrations/0003_ticket_is_sandbox.py similarity index 100% rename from smoothschedule/tickets/migrations/0003_ticket_is_sandbox.py rename to smoothschedule/smoothschedule/commerce/tickets/migrations/0003_ticket_is_sandbox.py diff --git a/smoothschedule/tickets/migrations/0004_ticketemailsettings_ticketcomment_source_and_more.py b/smoothschedule/smoothschedule/commerce/tickets/migrations/0004_ticketemailsettings_ticketcomment_source_and_more.py similarity index 100% rename from smoothschedule/tickets/migrations/0004_ticketemailsettings_ticketcomment_source_and_more.py rename to smoothschedule/smoothschedule/commerce/tickets/migrations/0004_ticketemailsettings_ticketcomment_source_and_more.py diff --git a/smoothschedule/tickets/migrations/0005_add_delete_after_processing.py b/smoothschedule/smoothschedule/commerce/tickets/migrations/0005_add_delete_after_processing.py similarity index 100% rename from smoothschedule/tickets/migrations/0005_add_delete_after_processing.py rename to smoothschedule/smoothschedule/commerce/tickets/migrations/0005_add_delete_after_processing.py diff --git a/smoothschedule/tickets/migrations/0006_add_external_email_fields.py b/smoothschedule/smoothschedule/commerce/tickets/migrations/0006_add_external_email_fields.py similarity index 100% rename from smoothschedule/tickets/migrations/0006_add_external_email_fields.py rename to smoothschedule/smoothschedule/commerce/tickets/migrations/0006_add_external_email_fields.py diff --git a/smoothschedule/tickets/migrations/0007_add_external_author_to_comment.py b/smoothschedule/smoothschedule/commerce/tickets/migrations/0007_add_external_author_to_comment.py similarity index 100% rename from smoothschedule/tickets/migrations/0007_add_external_author_to_comment.py rename to smoothschedule/smoothschedule/commerce/tickets/migrations/0007_add_external_author_to_comment.py diff --git a/smoothschedule/tickets/migrations/0008_add_smtp_settings.py b/smoothschedule/smoothschedule/commerce/tickets/migrations/0008_add_smtp_settings.py similarity index 100% rename from smoothschedule/tickets/migrations/0008_add_smtp_settings.py rename to smoothschedule/smoothschedule/commerce/tickets/migrations/0008_add_smtp_settings.py diff --git a/smoothschedule/tickets/migrations/0009_add_oauth_credential_to_email_settings.py b/smoothschedule/smoothschedule/commerce/tickets/migrations/0009_add_oauth_credential_to_email_settings.py similarity index 100% rename from smoothschedule/tickets/migrations/0009_add_oauth_credential_to_email_settings.py rename to smoothschedule/smoothschedule/commerce/tickets/migrations/0009_add_oauth_credential_to_email_settings.py diff --git a/smoothschedule/tickets/migrations/0010_ticketemailaddress_incomingticketemail_email_address_and_more.py b/smoothschedule/smoothschedule/commerce/tickets/migrations/0010_ticketemailaddress_incomingticketemail_email_address_and_more.py similarity index 100% rename from smoothschedule/tickets/migrations/0010_ticketemailaddress_incomingticketemail_email_address_and_more.py rename to smoothschedule/smoothschedule/commerce/tickets/migrations/0010_ticketemailaddress_incomingticketemail_email_address_and_more.py diff --git a/smoothschedule/tickets/migrations/0011_alter_ticketemailaddress_tenant.py b/smoothschedule/smoothschedule/commerce/tickets/migrations/0011_alter_ticketemailaddress_tenant.py similarity index 100% rename from smoothschedule/tickets/migrations/0011_alter_ticketemailaddress_tenant.py rename to smoothschedule/smoothschedule/commerce/tickets/migrations/0011_alter_ticketemailaddress_tenant.py diff --git a/smoothschedule/tickets/migrations/0012_migrate_email_settings_to_addresses.py b/smoothschedule/smoothschedule/commerce/tickets/migrations/0012_migrate_email_settings_to_addresses.py similarity index 100% rename from smoothschedule/tickets/migrations/0012_migrate_email_settings_to_addresses.py rename to smoothschedule/smoothschedule/commerce/tickets/migrations/0012_migrate_email_settings_to_addresses.py diff --git a/smoothschedule/tickets/migrations/0013_delete_ticketemailsettings.py b/smoothschedule/smoothschedule/commerce/tickets/migrations/0013_delete_ticketemailsettings.py similarity index 100% rename from smoothschedule/tickets/migrations/0013_delete_ticketemailsettings.py rename to smoothschedule/smoothschedule/commerce/tickets/migrations/0013_delete_ticketemailsettings.py diff --git a/smoothschedule/core/management/__init__.py b/smoothschedule/smoothschedule/commerce/tickets/migrations/__init__.py similarity index 100% rename from smoothschedule/core/management/__init__.py rename to smoothschedule/smoothschedule/commerce/tickets/migrations/__init__.py diff --git a/smoothschedule/tickets/models.py b/smoothschedule/smoothschedule/commerce/tickets/models.py similarity index 98% rename from smoothschedule/tickets/models.py rename to smoothschedule/smoothschedule/commerce/tickets/models.py index 7e0098f..855c0f4 100644 --- a/smoothschedule/tickets/models.py +++ b/smoothschedule/smoothschedule/commerce/tickets/models.py @@ -1,8 +1,8 @@ from django.db import models from django.utils.translation import gettext_lazy as _ from django.utils import timezone -from core.models import Tenant -from smoothschedule.users.models import User +from smoothschedule.identity.core.models import Tenant +from smoothschedule.identity.users.models import User class Ticket(models.Model): @@ -160,6 +160,7 @@ class Ticket(models.Model): resolved_at = models.DateTimeField(null=True, blank=True) class Meta: + app_label = 'tickets' ordering = ['-priority', '-created_at'] indexes = [ models.Index(fields=['tenant', 'status']), @@ -247,6 +248,7 @@ class TicketTemplate(models.Model): created_at = models.DateTimeField(auto_now_add=True) class Meta: + app_label = 'tickets' ordering = ['ticket_type', 'name'] def __str__(self): @@ -285,6 +287,7 @@ class CannedResponse(models.Model): created_at = models.DateTimeField(auto_now_add=True) class Meta: + app_label = 'tickets' ordering = ['-use_count', 'title'] def __str__(self): @@ -349,6 +352,7 @@ class TicketComment(models.Model): ) class Meta: + app_label = 'tickets' ordering = ['created_at'] @property @@ -495,6 +499,7 @@ class IncomingTicketEmail(models.Model): ) class Meta: + app_label = 'tickets' ordering = ['-received_at'] indexes = [ models.Index(fields=['message_id']), @@ -640,6 +645,7 @@ class TicketEmailAddress(models.Model): updated_at = models.DateTimeField(auto_now=True) class Meta: + app_label = 'tickets' ordering = ['-is_default', 'display_name'] unique_together = [['tenant', 'email_address']] indexes = [ diff --git a/smoothschedule/tickets/routing.py b/smoothschedule/smoothschedule/commerce/tickets/routing.py similarity index 100% rename from smoothschedule/tickets/routing.py rename to smoothschedule/smoothschedule/commerce/tickets/routing.py diff --git a/smoothschedule/tickets/serializers.py b/smoothschedule/smoothschedule/commerce/tickets/serializers.py similarity index 98% rename from smoothschedule/tickets/serializers.py rename to smoothschedule/smoothschedule/commerce/tickets/serializers.py index 5cf62c7..0f03d8b 100644 --- a/smoothschedule/tickets/serializers.py +++ b/smoothschedule/smoothschedule/commerce/tickets/serializers.py @@ -1,7 +1,7 @@ from rest_framework import serializers from .models import Ticket, TicketComment, TicketTemplate, CannedResponse, IncomingTicketEmail, TicketEmailAddress -from smoothschedule.users.models import User -from core.models import Tenant +from smoothschedule.identity.users.models import User +from smoothschedule.identity.core.models import Tenant class TicketCommentSerializer(serializers.ModelSerializer): author_email = serializers.ReadOnlyField(source='author.email') diff --git a/smoothschedule/tickets/signals.py b/smoothschedule/smoothschedule/commerce/tickets/signals.py similarity index 98% rename from smoothschedule/tickets/signals.py rename to smoothschedule/smoothschedule/commerce/tickets/signals.py index 7e6c5b2..63960e3 100644 --- a/smoothschedule/tickets/signals.py +++ b/smoothschedule/smoothschedule/commerce/tickets/signals.py @@ -8,7 +8,7 @@ from channels.layers import get_channel_layer from asgiref.sync import async_to_sync from .models import Ticket, TicketComment -from smoothschedule.users.models import User +from smoothschedule.identity.users.models import User logger = logging.getLogger(__name__) @@ -25,7 +25,7 @@ def is_notifications_available(): global _notifications_available if _notifications_available is None: try: - from notifications.models import Notification + from smoothschedule.communication.notifications.models import Notification # Check if the table exists by doing a simple query Notification.objects.exists() _notifications_available = True @@ -60,7 +60,7 @@ def create_notification(recipient, actor, verb, action_object, target, data): return try: - from notifications.models import Notification + from smoothschedule.communication.notifications.models import Notification Notification.objects.create( recipient=recipient, actor=actor, diff --git a/smoothschedule/tickets/tasks.py b/smoothschedule/smoothschedule/commerce/tickets/tasks.py similarity index 98% rename from smoothschedule/tickets/tasks.py rename to smoothschedule/smoothschedule/commerce/tickets/tasks.py index 34f920e..82d79e8 100644 --- a/smoothschedule/tickets/tasks.py +++ b/smoothschedule/smoothschedule/commerce/tickets/tasks.py @@ -33,7 +33,7 @@ def fetch_incoming_emails(self): """ from .email_receiver import TicketEmailReceiver, PlatformEmailReceiver from .models import TicketEmailAddress - from platform_admin.models import PlatformEmailAddress + from smoothschedule.platform.admin.models import PlatformEmailAddress total_processed = 0 results = [] diff --git a/smoothschedule/contracts/tests.py b/smoothschedule/smoothschedule/commerce/tickets/tests.py similarity index 100% rename from smoothschedule/contracts/tests.py rename to smoothschedule/smoothschedule/commerce/tickets/tests.py diff --git a/smoothschedule/tickets/urls.py b/smoothschedule/smoothschedule/commerce/tickets/urls.py similarity index 100% rename from smoothschedule/tickets/urls.py rename to smoothschedule/smoothschedule/commerce/tickets/urls.py diff --git a/smoothschedule/tickets/views.py b/smoothschedule/smoothschedule/commerce/tickets/views.py similarity index 99% rename from smoothschedule/tickets/views.py rename to smoothschedule/smoothschedule/commerce/tickets/views.py index fe72524..3f952eb 100644 --- a/smoothschedule/tickets/views.py +++ b/smoothschedule/smoothschedule/commerce/tickets/views.py @@ -7,8 +7,8 @@ from rest_framework.views import APIView from django.db.models import Q from rest_framework.filters import OrderingFilter, SearchFilter -from core.models import Tenant -from smoothschedule.users.models import User +from smoothschedule.identity.core.models import Tenant +from smoothschedule.identity.users.models import User from .models import Ticket, TicketComment, TicketTemplate, CannedResponse, IncomingTicketEmail, TicketEmailAddress from .serializers import ( TicketSerializer, TicketListSerializer, TicketCommentSerializer, @@ -941,7 +941,7 @@ class RefreshTicketEmailsView(APIView): ) from .email_receiver import PlatformEmailReceiver - from platform_admin.models import PlatformEmailAddress + from smoothschedule.platform.admin.models import PlatformEmailAddress results = [] total_processed = 0 diff --git a/smoothschedule/core/management/commands/__init__.py b/smoothschedule/smoothschedule/communication/__init__.py similarity index 100% rename from smoothschedule/core/management/commands/__init__.py rename to smoothschedule/smoothschedule/communication/__init__.py diff --git a/smoothschedule/core/migrations/__init__.py b/smoothschedule/smoothschedule/communication/credits/__init__.py similarity index 100% rename from smoothschedule/core/migrations/__init__.py rename to smoothschedule/smoothschedule/communication/credits/__init__.py diff --git a/smoothschedule/smoothschedule/comms_credits/admin.py b/smoothschedule/smoothschedule/communication/credits/admin.py similarity index 100% rename from smoothschedule/smoothschedule/comms_credits/admin.py rename to smoothschedule/smoothschedule/communication/credits/admin.py diff --git a/smoothschedule/smoothschedule/comms_credits/apps.py b/smoothschedule/smoothschedule/communication/credits/apps.py similarity index 68% rename from smoothschedule/smoothschedule/comms_credits/apps.py rename to smoothschedule/smoothschedule/communication/credits/apps.py index e800e82..310464d 100644 --- a/smoothschedule/smoothschedule/comms_credits/apps.py +++ b/smoothschedule/smoothschedule/communication/credits/apps.py @@ -3,5 +3,6 @@ from django.apps import AppConfig class CommsCreditsConfig(AppConfig): default_auto_field = 'django.db.models.BigAutoField' - name = 'smoothschedule.comms_credits' + name = 'smoothschedule.communication.credits' + label = 'comms_credits' verbose_name = 'Communication Credits' diff --git a/smoothschedule/smoothschedule/comms_credits/migrations/0001_initial.py b/smoothschedule/smoothschedule/communication/credits/migrations/0001_initial.py similarity index 100% rename from smoothschedule/smoothschedule/comms_credits/migrations/0001_initial.py rename to smoothschedule/smoothschedule/communication/credits/migrations/0001_initial.py diff --git a/smoothschedule/smoothschedule/comms_credits/migrations/0002_add_stripe_customer_id.py b/smoothschedule/smoothschedule/communication/credits/migrations/0002_add_stripe_customer_id.py similarity index 100% rename from smoothschedule/smoothschedule/comms_credits/migrations/0002_add_stripe_customer_id.py rename to smoothschedule/smoothschedule/communication/credits/migrations/0002_add_stripe_customer_id.py diff --git a/smoothschedule/notifications/__init__.py b/smoothschedule/smoothschedule/communication/credits/migrations/__init__.py similarity index 100% rename from smoothschedule/notifications/__init__.py rename to smoothschedule/smoothschedule/communication/credits/migrations/__init__.py diff --git a/smoothschedule/smoothschedule/comms_credits/models.py b/smoothschedule/smoothschedule/communication/credits/models.py similarity index 98% rename from smoothschedule/smoothschedule/comms_credits/models.py rename to smoothschedule/smoothschedule/communication/credits/models.py index 62ce2e7..8fbd479 100644 --- a/smoothschedule/smoothschedule/comms_credits/models.py +++ b/smoothschedule/smoothschedule/communication/credits/models.py @@ -109,6 +109,7 @@ class CommunicationCredits(models.Model): updated_at = models.DateTimeField(auto_now=True) class Meta: + app_label = 'comms_credits' verbose_name = 'Communication Credits' verbose_name_plural = 'Communication Credits' @@ -210,7 +211,7 @@ class CommunicationCredits(models.Model): def _send_low_balance_warning(self): """Send low balance warning email.""" - from smoothschedule.comms_credits.tasks import send_low_balance_warning + from smoothschedule.communication.credits.tasks import send_low_balance_warning send_low_balance_warning.delay(self.id) self.low_balance_warning_sent = True @@ -219,7 +220,7 @@ class CommunicationCredits(models.Model): def _trigger_auto_reload(self): """Trigger auto-reload of credits.""" - from smoothschedule.comms_credits.tasks import process_auto_reload + from smoothschedule.communication.credits.tasks import process_auto_reload process_auto_reload.delay(self.id) @@ -291,6 +292,7 @@ class CreditTransaction(models.Model): created_at = models.DateTimeField(auto_now_add=True) class Meta: + app_label = 'comms_credits' ordering = ['-created_at'] indexes = [ models.Index(fields=['credits', '-created_at']), @@ -383,6 +385,7 @@ class ProxyPhoneNumber(models.Model): updated_at = models.DateTimeField(auto_now=True) class Meta: + app_label = 'comms_credits' ordering = ['phone_number'] verbose_name = 'Proxy Phone Number' verbose_name_plural = 'Proxy Phone Numbers' @@ -495,6 +498,7 @@ class MaskedSession(models.Model): updated_at = models.DateTimeField(auto_now=True) class Meta: + app_label = 'comms_credits' ordering = ['-created_at'] indexes = [ models.Index(fields=['tenant', 'status']), diff --git a/smoothschedule/smoothschedule/comms_credits/tasks.py b/smoothschedule/smoothschedule/communication/credits/tasks.py similarity index 98% rename from smoothschedule/smoothschedule/comms_credits/tasks.py rename to smoothschedule/smoothschedule/communication/credits/tasks.py index 43cb2e4..9091079 100644 --- a/smoothschedule/smoothschedule/comms_credits/tasks.py +++ b/smoothschedule/smoothschedule/communication/credits/tasks.py @@ -20,7 +20,7 @@ def sync_twilio_usage_all_tenants(): 2. Calculate charges with markup 3. Deduct from tenant credits """ - from core.models import Tenant + from smoothschedule.identity.core.models import Tenant tenants = Tenant.objects.exclude(twilio_subaccount_sid='') @@ -46,7 +46,7 @@ def sync_twilio_usage_for_tenant(tenant_id): Fetches usage from Twilio API and deducts from credits. """ - from core.models import Tenant + from smoothschedule.identity.core.models import Tenant from .models import CommunicationCredits try: @@ -219,7 +219,7 @@ def process_auto_reload(credits_id): try: # Get Stripe API key from platform settings - from platform_admin.models import PlatformSettings + from smoothschedule.platform.admin.models import PlatformSettings platform_settings = PlatformSettings.get_instance() stripe.api_key = platform_settings.get_stripe_secret_key() @@ -373,7 +373,7 @@ def create_twilio_subaccount(tenant_id): Called when SMS/calling is first enabled for a tenant. """ - from core.models import Tenant + from smoothschedule.identity.core.models import Tenant from twilio.rest import Client try: diff --git a/smoothschedule/smoothschedule/comms_credits/urls.py b/smoothschedule/smoothschedule/communication/credits/urls.py similarity index 100% rename from smoothschedule/smoothschedule/comms_credits/urls.py rename to smoothschedule/smoothschedule/communication/credits/urls.py diff --git a/smoothschedule/smoothschedule/comms_credits/views.py b/smoothschedule/smoothschedule/communication/credits/views.py similarity index 100% rename from smoothschedule/smoothschedule/comms_credits/views.py rename to smoothschedule/smoothschedule/communication/credits/views.py diff --git a/smoothschedule/notifications/migrations/__init__.py b/smoothschedule/smoothschedule/communication/messaging/__init__.py similarity index 100% rename from smoothschedule/notifications/migrations/__init__.py rename to smoothschedule/smoothschedule/communication/messaging/__init__.py diff --git a/smoothschedule/contracts/admin.py b/smoothschedule/smoothschedule/communication/messaging/admin.py similarity index 100% rename from smoothschedule/contracts/admin.py rename to smoothschedule/smoothschedule/communication/messaging/admin.py diff --git a/smoothschedule/communication/apps.py b/smoothschedule/smoothschedule/communication/messaging/apps.py similarity index 62% rename from smoothschedule/communication/apps.py rename to smoothschedule/smoothschedule/communication/messaging/apps.py index 923ff5b..37c3236 100644 --- a/smoothschedule/communication/apps.py +++ b/smoothschedule/smoothschedule/communication/messaging/apps.py @@ -3,4 +3,5 @@ from django.apps import AppConfig class CommunicationConfig(AppConfig): default_auto_field = 'django.db.models.BigAutoField' - name = 'communication' + name = 'smoothschedule.communication.messaging' + label = 'communication' diff --git a/smoothschedule/communication/migrations/0001_initial.py b/smoothschedule/smoothschedule/communication/messaging/migrations/0001_initial.py similarity index 100% rename from smoothschedule/communication/migrations/0001_initial.py rename to smoothschedule/smoothschedule/communication/messaging/migrations/0001_initial.py diff --git a/smoothschedule/payments/__init__.py b/smoothschedule/smoothschedule/communication/messaging/migrations/__init__.py similarity index 100% rename from smoothschedule/payments/__init__.py rename to smoothschedule/smoothschedule/communication/messaging/migrations/__init__.py diff --git a/smoothschedule/communication/models.py b/smoothschedule/smoothschedule/communication/messaging/models.py similarity index 98% rename from smoothschedule/communication/models.py rename to smoothschedule/smoothschedule/communication/messaging/models.py index 2570b62..dc4a104 100644 --- a/smoothschedule/communication/models.py +++ b/smoothschedule/smoothschedule/communication/messaging/models.py @@ -83,6 +83,7 @@ class CommunicationSession(models.Model): ) class Meta: + app_label = 'communication' ordering = ['-created_at'] indexes = [ models.Index(fields=['is_active', 'created_at']), diff --git a/smoothschedule/communication/services.py b/smoothschedule/smoothschedule/communication/messaging/services.py similarity index 99% rename from smoothschedule/communication/services.py rename to smoothschedule/smoothschedule/communication/messaging/services.py index 5ae469c..072d792 100644 --- a/smoothschedule/communication/services.py +++ b/smoothschedule/smoothschedule/communication/messaging/services.py @@ -57,7 +57,7 @@ class TwilioService: PermissionError: If tenant doesn't have masked calling feature """ from django.db import connection - from core.models import Tenant + from smoothschedule.identity.core.models import Tenant from rest_framework.exceptions import PermissionDenied # Check feature permission diff --git a/smoothschedule/notifications/tests.py b/smoothschedule/smoothschedule/communication/messaging/tests.py similarity index 100% rename from smoothschedule/notifications/tests.py rename to smoothschedule/smoothschedule/communication/messaging/tests.py diff --git a/smoothschedule/communication/views.py b/smoothschedule/smoothschedule/communication/messaging/views.py similarity index 100% rename from smoothschedule/communication/views.py rename to smoothschedule/smoothschedule/communication/messaging/views.py diff --git a/smoothschedule/smoothschedule/field_mobile/__init__.py b/smoothschedule/smoothschedule/communication/mobile/__init__.py similarity index 100% rename from smoothschedule/smoothschedule/field_mobile/__init__.py rename to smoothschedule/smoothschedule/communication/mobile/__init__.py diff --git a/smoothschedule/smoothschedule/field_mobile/apps.py b/smoothschedule/smoothschedule/communication/mobile/apps.py similarity index 84% rename from smoothschedule/smoothschedule/field_mobile/apps.py rename to smoothschedule/smoothschedule/communication/mobile/apps.py index 7ad34df..e7f2afb 100644 --- a/smoothschedule/smoothschedule/field_mobile/apps.py +++ b/smoothschedule/smoothschedule/communication/mobile/apps.py @@ -3,7 +3,7 @@ from django.apps import AppConfig class FieldMobileConfig(AppConfig): default_auto_field = 'django.db.models.BigAutoField' - name = 'smoothschedule.field_mobile' + name = 'smoothschedule.communication.mobile' label = 'field_mobile' verbose_name = 'Field Mobile App' diff --git a/smoothschedule/smoothschedule/field_mobile/migrations/0001_initial.py b/smoothschedule/smoothschedule/communication/mobile/migrations/0001_initial.py similarity index 100% rename from smoothschedule/smoothschedule/field_mobile/migrations/0001_initial.py rename to smoothschedule/smoothschedule/communication/mobile/migrations/0001_initial.py diff --git a/smoothschedule/payments/migrations/__init__.py b/smoothschedule/smoothschedule/communication/mobile/migrations/__init__.py similarity index 100% rename from smoothschedule/payments/migrations/__init__.py rename to smoothschedule/smoothschedule/communication/mobile/migrations/__init__.py diff --git a/smoothschedule/smoothschedule/field_mobile/models.py b/smoothschedule/smoothschedule/communication/mobile/models.py similarity index 98% rename from smoothschedule/smoothschedule/field_mobile/models.py rename to smoothschedule/smoothschedule/communication/mobile/models.py index 7ce6d0e..f17e29b 100644 --- a/smoothschedule/smoothschedule/field_mobile/models.py +++ b/smoothschedule/smoothschedule/communication/mobile/models.py @@ -81,6 +81,7 @@ class EventStatusHistory(models.Model): ) class Meta: + app_label = 'field_mobile' ordering = ['-changed_at'] indexes = [ models.Index(fields=['tenant', 'event_id']), @@ -174,6 +175,7 @@ class EmployeeLocationUpdate(models.Model): ) class Meta: + app_label = 'field_mobile' ordering = ['-timestamp'] indexes = [ models.Index(fields=['tenant', 'event_id', '-timestamp']), @@ -315,6 +317,7 @@ class FieldCallLog(models.Model): ended_at = models.DateTimeField(null=True, blank=True) class Meta: + app_label = 'field_mobile' ordering = ['-initiated_at'] indexes = [ models.Index(fields=['tenant', 'event_id']), diff --git a/smoothschedule/smoothschedule/field_mobile/serializers.py b/smoothschedule/smoothschedule/communication/mobile/serializers.py similarity index 95% rename from smoothschedule/smoothschedule/field_mobile/serializers.py rename to smoothschedule/smoothschedule/communication/mobile/serializers.py index c5fa534..41607d8 100644 --- a/smoothschedule/smoothschedule/field_mobile/serializers.py +++ b/smoothschedule/smoothschedule/communication/mobile/serializers.py @@ -6,8 +6,8 @@ Serializers for the field employee mobile app API. from rest_framework import serializers from django.utils import timezone -from schedule.models import Event, Service, Participant -from smoothschedule.field_mobile.models import ( +from smoothschedule.scheduling.schedule.models import Event, Service, Participant +from smoothschedule.communication.mobile.models import ( EventStatusHistory, EmployeeLocationUpdate, FieldCallLog, @@ -110,7 +110,7 @@ class JobListSerializer(serializers.ModelSerializer): def get_allowed_transitions(self, obj): """Get list of statuses this job can transition to.""" - from smoothschedule.field_mobile.services import StatusMachine + from smoothschedule.communication.mobile.services import StatusMachine # Get the valid transitions without needing user context return StatusMachine.VALID_TRANSITIONS.get(obj.status, []) @@ -118,7 +118,7 @@ class JobListSerializer(serializers.ModelSerializer): def _get_customer_participant(self, obj): """Get the customer User from participants.""" from django.contrib.contenttypes.models import ContentType - from smoothschedule.users.models import User + from smoothschedule.identity.users.models import User if not hasattr(self, '_customer_cache'): self._customer_cache = {} @@ -196,8 +196,8 @@ class JobDetailSerializer(serializers.ModelSerializer): def get_assigned_staff(self, obj): """Get list of assigned staff members.""" from django.contrib.contenttypes.models import ContentType - from smoothschedule.users.models import User - from schedule.models import Resource + from smoothschedule.identity.users.models import User + from smoothschedule.scheduling.schedule.models import Resource staff = [] @@ -239,12 +239,12 @@ class JobDetailSerializer(serializers.ModelSerializer): return None def get_allowed_transitions(self, obj): - from smoothschedule.field_mobile.services import StatusMachine + from smoothschedule.communication.mobile.services import StatusMachine return StatusMachine.VALID_TRANSITIONS.get(obj.status, []) def get_can_track_location(self, obj): """Check if location tracking is allowed for current status.""" - from smoothschedule.field_mobile.services import StatusMachine + from smoothschedule.communication.mobile.services import StatusMachine return obj.status in StatusMachine.TRACKING_STATUSES def get_has_active_call_session(self, obj): @@ -253,7 +253,7 @@ class JobDetailSerializer(serializers.ModelSerializer): if not tenant: return False - from smoothschedule.comms_credits.models import MaskedSession + from smoothschedule.communication.credits.models import MaskedSession return MaskedSession.objects.filter( tenant=tenant, event_id=obj.id, @@ -305,7 +305,7 @@ class JobDetailSerializer(serializers.ModelSerializer): def _get_customer_participant(self, obj): from django.contrib.contenttypes.models import ContentType - from smoothschedule.users.models import User + from smoothschedule.identity.users.models import User try: user_ct = ContentType.objects.get_for_model(User) @@ -324,7 +324,7 @@ class JobDetailSerializer(serializers.ModelSerializer): Returns True if the user's linked resource has user_can_edit_schedule=True. """ from django.contrib.contenttypes.models import ContentType - from schedule.models import Resource + from smoothschedule.scheduling.schedule.models import Resource # Get the current user from context request = self.context.get('request') diff --git a/smoothschedule/smoothschedule/field_mobile/services/__init__.py b/smoothschedule/smoothschedule/communication/mobile/services/__init__.py similarity index 100% rename from smoothschedule/smoothschedule/field_mobile/services/__init__.py rename to smoothschedule/smoothschedule/communication/mobile/services/__init__.py diff --git a/smoothschedule/smoothschedule/field_mobile/services/status_machine.py b/smoothschedule/smoothschedule/communication/mobile/services/status_machine.py similarity index 95% rename from smoothschedule/smoothschedule/field_mobile/services/status_machine.py rename to smoothschedule/smoothschedule/communication/mobile/services/status_machine.py index 4a835b7..01a12cb 100644 --- a/smoothschedule/smoothschedule/field_mobile/services/status_machine.py +++ b/smoothschedule/smoothschedule/communication/mobile/services/status_machine.py @@ -8,8 +8,8 @@ from django.db import transaction from typing import Optional, Tuple from decimal import Decimal -from schedule.models import Event -from smoothschedule.field_mobile.models import EventStatusHistory, EmployeeLocationUpdate +from smoothschedule.scheduling.schedule.models import Event +from smoothschedule.communication.mobile.models import EventStatusHistory, EmployeeLocationUpdate class StatusTransitionError(Exception): @@ -124,8 +124,8 @@ class StatusMachine: - User is linked to a Resource that is a participant """ from django.contrib.contenttypes.models import ContentType - from schedule.models import Participant, Resource - from smoothschedule.users.models import User + from smoothschedule.scheduling.schedule.models import Participant, Resource + from smoothschedule.identity.users.models import User # Check if user is directly a participant user_ct = ContentType.objects.get_for_model(User) @@ -158,7 +158,7 @@ class StatusMachine: Returns: Tuple of (is_allowed, reason_if_not) """ - from smoothschedule.users.models import User + from smoothschedule.identity.users.models import User # Owners and managers can always change status if self.user.role in [User.Role.TENANT_OWNER, User.Role.TENANT_MANAGER]: @@ -235,7 +235,7 @@ class StatusMachine: self._stop_location_tracking(event) # Emit status change signal (triggers notifications and plugin hooks) - from schedule.signals import emit_status_change + from smoothschedule.scheduling.schedule.signals import emit_status_change emit_status_change( event=event, old_status=old_status, diff --git a/smoothschedule/smoothschedule/field_mobile/services/twilio_calls.py b/smoothschedule/smoothschedule/communication/mobile/services/twilio_calls.py similarity index 95% rename from smoothschedule/smoothschedule/field_mobile/services/twilio_calls.py rename to smoothschedule/smoothschedule/communication/mobile/services/twilio_calls.py index 9ed0472..db06f6a 100644 --- a/smoothschedule/smoothschedule/field_mobile/services/twilio_calls.py +++ b/smoothschedule/smoothschedule/communication/mobile/services/twilio_calls.py @@ -90,7 +90,7 @@ class TwilioFieldCallService: Returns: MaskedSession instance """ - from smoothschedule.comms_credits.models import MaskedSession, ProxyPhoneNumber + from smoothschedule.communication.credits.models import MaskedSession, ProxyPhoneNumber # Check for existing active session existing = MaskedSession.objects.filter( @@ -145,7 +145,7 @@ class TwilioFieldCallService: 1. Numbers already assigned to this tenant 2. Numbers in the shared pool (AVAILABLE status) """ - from smoothschedule.comms_credits.models import ProxyPhoneNumber + from smoothschedule.communication.credits.models import ProxyPhoneNumber # First, try tenant's assigned numbers tenant_number = ProxyPhoneNumber.objects.filter( @@ -180,7 +180,7 @@ class TwilioFieldCallService: Args: estimated_cost_cents: Estimated cost of the call/SMS """ - from smoothschedule.comms_credits.models import CommunicationCredits + from smoothschedule.communication.credits.models import CommunicationCredits try: credits = CommunicationCredits.objects.get(tenant=self.tenant) @@ -202,8 +202,8 @@ class TwilioFieldCallService: Looks up the customer participant and returns their phone. """ from django.contrib.contenttypes.models import ContentType - from schedule.models import Event, Participant - from smoothschedule.users.models import User + from smoothschedule.scheduling.schedule.models import Event, Participant + from smoothschedule.identity.users.models import User from django_tenants.utils import schema_context with schema_context(self.tenant.schema_name): @@ -248,7 +248,7 @@ class TwilioFieldCallService: Returns: Dict with call_sid, proxy_number, status """ - from smoothschedule.field_mobile.models import FieldCallLog + from smoothschedule.communication.mobile.models import FieldCallLog # Check permissions and credits self._check_feature_permission() @@ -344,7 +344,7 @@ class TwilioFieldCallService: Returns: Dict with message_sid, status """ - from smoothschedule.field_mobile.models import FieldCallLog + from smoothschedule.communication.mobile.models import FieldCallLog # Check permissions and credits self._check_feature_permission() @@ -425,7 +425,7 @@ class TwilioFieldCallService: Returns None if no active session exists. """ - from smoothschedule.comms_credits.models import MaskedSession + from smoothschedule.communication.credits.models import MaskedSession return MaskedSession.objects.filter( tenant=self.tenant, @@ -440,7 +440,7 @@ class TwilioFieldCallService: Called when a job is completed to stop allowing calls/SMS. """ - from smoothschedule.comms_credits.models import MaskedSession + from smoothschedule.communication.credits.models import MaskedSession session = self.get_session_for_event(event_id) if session: @@ -458,7 +458,7 @@ class TwilioFieldCallService: Returns: List of FieldCallLog records """ - from smoothschedule.field_mobile.models import FieldCallLog + from smoothschedule.communication.mobile.models import FieldCallLog return list( FieldCallLog.objects.filter( @@ -507,7 +507,7 @@ def handle_incoming_call(session_id: int, from_number: str) -> str: Returns: TwiML response string """ - from smoothschedule.comms_credits.models import MaskedSession + from smoothschedule.communication.credits.models import MaskedSession from twilio.twiml.voice_response import VoiceResponse response = VoiceResponse() @@ -557,7 +557,7 @@ def handle_incoming_sms(session_id: int, from_number: str, body: str) -> str: Returns: TwiML response string (empty for SMS) """ - from smoothschedule.comms_credits.models import MaskedSession + from smoothschedule.communication.credits.models import MaskedSession from twilio.rest import Client from django.conf import settings as django_settings diff --git a/smoothschedule/smoothschedule/field_mobile/tasks.py b/smoothschedule/smoothschedule/communication/mobile/tasks.py similarity index 93% rename from smoothschedule/smoothschedule/field_mobile/tasks.py rename to smoothschedule/smoothschedule/communication/mobile/tasks.py index 462f266..4f9597d 100644 --- a/smoothschedule/smoothschedule/field_mobile/tasks.py +++ b/smoothschedule/smoothschedule/communication/mobile/tasks.py @@ -21,11 +21,11 @@ def send_customer_status_notification(tenant_id, event_id, notification_type): event_id: The event/job ID notification_type: One of 'en_route_notification', 'arrived_notification', 'completed_notification' """ - from core.models import Tenant + from smoothschedule.identity.core.models import Tenant from django_tenants.utils import schema_context - from schedule.models import Event, Participant + from smoothschedule.scheduling.schedule.models import Event, Participant from django.contrib.contenttypes.models import ContentType - from smoothschedule.users.models import User + from smoothschedule.identity.users.models import User try: tenant = Tenant.objects.get(id=tenant_id) @@ -118,8 +118,8 @@ def send_sms_notification(tenant_id, phone_number, message): phone_number: Recipient phone number message: SMS message body """ - from core.models import Tenant - from smoothschedule.comms_credits.models import CommunicationCredits + from smoothschedule.identity.core.models import Tenant + from smoothschedule.communication.credits.models import CommunicationCredits try: tenant = Tenant.objects.get(id=tenant_id) @@ -190,7 +190,7 @@ def send_email_notification(tenant_id, email, subject, message, customer_name='C message: Email body customer_name: Customer's name for personalization """ - from core.models import Tenant + from smoothschedule.identity.core.models import Tenant from django.core.mail import send_mail try: @@ -237,7 +237,7 @@ def cleanup_old_location_data(days_to_keep=30): Args: days_to_keep: Number of days of data to retain (default 30) """ - from smoothschedule.field_mobile.models import EmployeeLocationUpdate + from smoothschedule.communication.mobile.models import EmployeeLocationUpdate cutoff = timezone.now() - timezone.timedelta(days=days_to_keep) @@ -259,7 +259,7 @@ def cleanup_old_status_history(days_to_keep=365): Args: days_to_keep: Number of days of data to retain (default 365) """ - from smoothschedule.field_mobile.models import EventStatusHistory + from smoothschedule.communication.mobile.models import EventStatusHistory cutoff = timezone.now() - timezone.timedelta(days=days_to_keep) diff --git a/smoothschedule/smoothschedule/field_mobile/urls.py b/smoothschedule/smoothschedule/communication/mobile/urls.py similarity index 100% rename from smoothschedule/smoothschedule/field_mobile/urls.py rename to smoothschedule/smoothschedule/communication/mobile/urls.py diff --git a/smoothschedule/smoothschedule/field_mobile/views.py b/smoothschedule/smoothschedule/communication/mobile/views.py similarity index 96% rename from smoothschedule/smoothschedule/field_mobile/views.py rename to smoothschedule/smoothschedule/communication/mobile/views.py index 0ef2c93..3f1c0af 100644 --- a/smoothschedule/smoothschedule/field_mobile/views.py +++ b/smoothschedule/smoothschedule/communication/mobile/views.py @@ -19,14 +19,14 @@ from rest_framework.response import Response from django_tenants.utils import schema_context -from schedule.models import Event, Participant, Resource -from smoothschedule.users.models import User -from smoothschedule.field_mobile.models import ( +from smoothschedule.scheduling.schedule.models import Event, Participant, Resource +from smoothschedule.identity.users.models import User +from smoothschedule.communication.mobile.models import ( EventStatusHistory, EmployeeLocationUpdate, FieldCallLog, ) -from smoothschedule.field_mobile.serializers import ( +from smoothschedule.communication.mobile.serializers import ( JobListSerializer, JobDetailSerializer, SetStatusSerializer, @@ -41,9 +41,9 @@ from smoothschedule.field_mobile.serializers import ( CallHistorySerializer, EmployeeProfileSerializer, ) -from smoothschedule.field_mobile.services import StatusMachine, TwilioFieldCallService -from smoothschedule.field_mobile.services.status_machine import StatusTransitionError -from smoothschedule.field_mobile.services.twilio_calls import TwilioFieldCallError +from smoothschedule.communication.mobile.services import StatusMachine, TwilioFieldCallService +from smoothschedule.communication.mobile.services.status_machine import StatusTransitionError +from smoothschedule.communication.mobile.services.twilio_calls import TwilioFieldCallError logger = logging.getLogger(__name__) @@ -467,8 +467,8 @@ def location_update_view(request, job_id): # Broadcast location update via WebSocket # Find the resource linked to this user and broadcast to watchers - from schedule.models import Resource - from schedule.consumers import broadcast_resource_location_update + from smoothschedule.scheduling.schedule.models import Resource + from smoothschedule.scheduling.schedule.consumers import broadcast_resource_location_update from asgiref.sync import async_to_sync user_resources = Resource.objects.filter(user=user) @@ -702,7 +702,7 @@ def twilio_voice_webhook(request, session_id): Called by Twilio when a call is initiated or received. Returns TwiML to route the call. """ - from smoothschedule.field_mobile.services.twilio_calls import handle_incoming_call + from smoothschedule.communication.mobile.services.twilio_calls import handle_incoming_call from_number = request.data.get('From', '') twiml = handle_incoming_call(session_id, from_number) @@ -774,7 +774,7 @@ def twilio_sms_webhook(request, session_id): Forwards the SMS to the appropriate party. """ - from smoothschedule.field_mobile.services.twilio_calls import handle_incoming_sms + from smoothschedule.communication.mobile.services.twilio_calls import handle_incoming_sms from_number = request.data.get('From', '') body = request.data.get('Body', '') diff --git a/smoothschedule/platform_admin/management/__init__.py b/smoothschedule/smoothschedule/communication/notifications/__init__.py similarity index 100% rename from smoothschedule/platform_admin/management/__init__.py rename to smoothschedule/smoothschedule/communication/notifications/__init__.py diff --git a/smoothschedule/notifications/admin.py b/smoothschedule/smoothschedule/communication/notifications/admin.py similarity index 100% rename from smoothschedule/notifications/admin.py rename to smoothschedule/smoothschedule/communication/notifications/admin.py diff --git a/smoothschedule/notifications/apps.py b/smoothschedule/smoothschedule/communication/notifications/apps.py similarity index 60% rename from smoothschedule/notifications/apps.py rename to smoothschedule/smoothschedule/communication/notifications/apps.py index 001b4f9..8f869ee 100644 --- a/smoothschedule/notifications/apps.py +++ b/smoothschedule/smoothschedule/communication/notifications/apps.py @@ -3,4 +3,5 @@ from django.apps import AppConfig class NotificationsConfig(AppConfig): default_auto_field = 'django.db.models.BigAutoField' - name = 'notifications' + name = 'smoothschedule.communication.notifications' + label = 'notifications' diff --git a/smoothschedule/notifications/migrations/0001_initial.py b/smoothschedule/smoothschedule/communication/notifications/migrations/0001_initial.py similarity index 100% rename from smoothschedule/notifications/migrations/0001_initial.py rename to smoothschedule/smoothschedule/communication/notifications/migrations/0001_initial.py diff --git a/smoothschedule/platform_admin/management/commands/__init__.py b/smoothschedule/smoothschedule/communication/notifications/migrations/__init__.py similarity index 100% rename from smoothschedule/platform_admin/management/commands/__init__.py rename to smoothschedule/smoothschedule/communication/notifications/migrations/__init__.py diff --git a/smoothschedule/notifications/models.py b/smoothschedule/smoothschedule/communication/notifications/models.py similarity index 96% rename from smoothschedule/notifications/models.py rename to smoothschedule/smoothschedule/communication/notifications/models.py index ee2df2d..4a5e9d7 100644 --- a/smoothschedule/notifications/models.py +++ b/smoothschedule/smoothschedule/communication/notifications/models.py @@ -2,7 +2,7 @@ from django.db import models from django.utils.translation import gettext_lazy as _ from django.contrib.contenttypes.fields import GenericForeignKey from django.contrib.contenttypes.models import ContentType -from smoothschedule.users.models import User +from smoothschedule.identity.users.models import User class Notification(models.Model): """ @@ -57,6 +57,7 @@ class Notification(models.Model): ) class Meta: + app_label = 'notifications' ordering = ['-timestamp'] indexes = [ models.Index(fields=['recipient', 'read', 'timestamp']), diff --git a/smoothschedule/notifications/serializers.py b/smoothschedule/smoothschedule/communication/notifications/serializers.py similarity index 100% rename from smoothschedule/notifications/serializers.py rename to smoothschedule/smoothschedule/communication/notifications/serializers.py diff --git a/smoothschedule/payments/tests.py b/smoothschedule/smoothschedule/communication/notifications/tests.py similarity index 100% rename from smoothschedule/payments/tests.py rename to smoothschedule/smoothschedule/communication/notifications/tests.py diff --git a/smoothschedule/notifications/urls.py b/smoothschedule/smoothschedule/communication/notifications/urls.py similarity index 100% rename from smoothschedule/notifications/urls.py rename to smoothschedule/smoothschedule/communication/notifications/urls.py diff --git a/smoothschedule/notifications/views.py b/smoothschedule/smoothschedule/communication/notifications/views.py similarity index 100% rename from smoothschedule/notifications/views.py rename to smoothschedule/smoothschedule/communication/notifications/views.py diff --git a/smoothschedule/smoothschedule/conftest.py b/smoothschedule/smoothschedule/conftest.py index 8a492ad..d1f0f33 100644 --- a/smoothschedule/smoothschedule/conftest.py +++ b/smoothschedule/smoothschedule/conftest.py @@ -1,7 +1,7 @@ import pytest -from smoothschedule.users.models import User -from smoothschedule.users.tests.factories import UserFactory +from smoothschedule.identity.users.models import User +from smoothschedule.identity.users.tests.factories import UserFactory @pytest.fixture(autouse=True) diff --git a/smoothschedule/platform_admin/migrations/__init__.py b/smoothschedule/smoothschedule/identity/__init__.py similarity index 100% rename from smoothschedule/platform_admin/migrations/__init__.py rename to smoothschedule/smoothschedule/identity/__init__.py diff --git a/smoothschedule/core/__init__.py b/smoothschedule/smoothschedule/identity/core/__init__.py similarity index 100% rename from smoothschedule/core/__init__.py rename to smoothschedule/smoothschedule/identity/core/__init__.py diff --git a/smoothschedule/core/admin.py b/smoothschedule/smoothschedule/identity/core/admin.py similarity index 100% rename from smoothschedule/core/admin.py rename to smoothschedule/smoothschedule/identity/core/admin.py diff --git a/smoothschedule/core/api_views.py b/smoothschedule/smoothschedule/identity/core/api_views.py similarity index 98% rename from smoothschedule/core/api_views.py rename to smoothschedule/smoothschedule/identity/core/api_views.py index 96023dd..07a23c4 100644 --- a/smoothschedule/core/api_views.py +++ b/smoothschedule/smoothschedule/identity/core/api_views.py @@ -9,7 +9,7 @@ from rest_framework.response import Response from .quota_service import QuotaService from .models import QuotaOverage -from smoothschedule.users.models import User +from smoothschedule.identity.users.models import User def is_owner_or_manager(user): @@ -109,7 +109,7 @@ def quota_resources_view(request, quota_type): }) elif quota_type == 'MAX_RESOURCES': - from schedule.models import Resource + from smoothschedule.scheduling.schedule.models import Resource for r in Resource.objects.all().order_by('created_at'): resources.append({ 'id': r.id, @@ -121,7 +121,7 @@ def quota_resources_view(request, quota_type): }) elif quota_type == 'MAX_SERVICES': - from schedule.models import Service + from smoothschedule.scheduling.schedule.models import Service for s in Service.objects.all().order_by('created_at'): resources.append({ 'id': s.id, diff --git a/smoothschedule/core/apps.py b/smoothschedule/smoothschedule/identity/core/apps.py similarity index 85% rename from smoothschedule/core/apps.py rename to smoothschedule/smoothschedule/identity/core/apps.py index 764951d..b77ec3a 100644 --- a/smoothschedule/core/apps.py +++ b/smoothschedule/smoothschedule/identity/core/apps.py @@ -6,7 +6,8 @@ from django.apps import AppConfig class CoreConfig(AppConfig): default_auto_field = 'django.db.models.BigAutoField' - name = 'core' + name = 'smoothschedule.identity.core' + label = 'core' verbose_name = 'Smooth Schedule Core' def ready(self): diff --git a/smoothschedule/core/email_autoconfig.py b/smoothschedule/smoothschedule/identity/core/email_autoconfig.py similarity index 100% rename from smoothschedule/core/email_autoconfig.py rename to smoothschedule/smoothschedule/identity/core/email_autoconfig.py diff --git a/smoothschedule/schedule/__init__.py b/smoothschedule/smoothschedule/identity/core/management/__init__.py similarity index 100% rename from smoothschedule/schedule/__init__.py rename to smoothschedule/smoothschedule/identity/core/management/__init__.py diff --git a/smoothschedule/schedule/management/__init__.py b/smoothschedule/smoothschedule/identity/core/management/commands/__init__.py similarity index 100% rename from smoothschedule/schedule/management/__init__.py rename to smoothschedule/smoothschedule/identity/core/management/commands/__init__.py diff --git a/smoothschedule/core/management/commands/create_sandbox_schemas.py b/smoothschedule/smoothschedule/identity/core/management/commands/create_sandbox_schemas.py similarity index 98% rename from smoothschedule/core/management/commands/create_sandbox_schemas.py rename to smoothschedule/smoothschedule/identity/core/management/commands/create_sandbox_schemas.py index ea417d1..49ff3fd 100644 --- a/smoothschedule/core/management/commands/create_sandbox_schemas.py +++ b/smoothschedule/smoothschedule/identity/core/management/commands/create_sandbox_schemas.py @@ -19,7 +19,7 @@ Usage: from django.core.management.base import BaseCommand from django.core.management import call_command from django.db import connection -from core.models import Tenant +from smoothschedule.identity.core.models import Tenant class Command(BaseCommand): diff --git a/smoothschedule/core/management/commands/setup_quota_tasks.py b/smoothschedule/smoothschedule/identity/core/management/commands/setup_quota_tasks.py similarity index 100% rename from smoothschedule/core/management/commands/setup_quota_tasks.py rename to smoothschedule/smoothschedule/identity/core/management/commands/setup_quota_tasks.py diff --git a/smoothschedule/core/middleware.py b/smoothschedule/smoothschedule/identity/core/middleware.py similarity index 99% rename from smoothschedule/core/middleware.py rename to smoothschedule/smoothschedule/identity/core/middleware.py index c257aad..1a6c4fa 100644 --- a/smoothschedule/core/middleware.py +++ b/smoothschedule/smoothschedule/identity/core/middleware.py @@ -221,7 +221,7 @@ class MasqueradeAuditMiddleware(MiddlewareMixin): original_user_id = hijack_history[0] # Load the actual admin user - from users.models import User + from smoothschedule.identity.users.models import User try: actual_user = User.objects.get(pk=original_user_id) request.actual_user = actual_user diff --git a/smoothschedule/core/migrations/0001_initial.py b/smoothschedule/smoothschedule/identity/core/migrations/0001_initial.py similarity index 100% rename from smoothschedule/core/migrations/0001_initial.py rename to smoothschedule/smoothschedule/identity/core/migrations/0001_initial.py diff --git a/smoothschedule/core/migrations/0002_tierlimit.py b/smoothschedule/smoothschedule/identity/core/migrations/0002_tierlimit.py similarity index 100% rename from smoothschedule/core/migrations/0002_tierlimit.py rename to smoothschedule/smoothschedule/identity/core/migrations/0002_tierlimit.py diff --git a/smoothschedule/core/migrations/0003_tenant_logo_tenant_logo_display_mode_and_more.py b/smoothschedule/smoothschedule/identity/core/migrations/0003_tenant_logo_tenant_logo_display_mode_and_more.py similarity index 100% rename from smoothschedule/core/migrations/0003_tenant_logo_tenant_logo_display_mode_and_more.py rename to smoothschedule/smoothschedule/identity/core/migrations/0003_tenant_logo_tenant_logo_display_mode_and_more.py diff --git a/smoothschedule/core/migrations/0004_tenant_email_logo_alter_tenant_logo.py b/smoothschedule/smoothschedule/identity/core/migrations/0004_tenant_email_logo_alter_tenant_logo.py similarity index 100% rename from smoothschedule/core/migrations/0004_tenant_email_logo_alter_tenant_logo.py rename to smoothschedule/smoothschedule/identity/core/migrations/0004_tenant_email_logo_alter_tenant_logo.py diff --git a/smoothschedule/core/migrations/0005_add_oauth_settings_to_tenant.py b/smoothschedule/smoothschedule/identity/core/migrations/0005_add_oauth_settings_to_tenant.py similarity index 100% rename from smoothschedule/core/migrations/0005_add_oauth_settings_to_tenant.py rename to smoothschedule/smoothschedule/identity/core/migrations/0005_add_oauth_settings_to_tenant.py diff --git a/smoothschedule/core/migrations/0006_add_can_manage_oauth_credentials.py b/smoothschedule/smoothschedule/identity/core/migrations/0006_add_can_manage_oauth_credentials.py similarity index 100% rename from smoothschedule/core/migrations/0006_add_can_manage_oauth_credentials.py rename to smoothschedule/smoothschedule/identity/core/migrations/0006_add_can_manage_oauth_credentials.py diff --git a/smoothschedule/core/migrations/0007_add_tenant_permissions.py b/smoothschedule/smoothschedule/identity/core/migrations/0007_add_tenant_permissions.py similarity index 100% rename from smoothschedule/core/migrations/0007_add_tenant_permissions.py rename to smoothschedule/smoothschedule/identity/core/migrations/0007_add_tenant_permissions.py diff --git a/smoothschedule/core/migrations/0008_add_sandbox_fields.py b/smoothschedule/smoothschedule/identity/core/migrations/0008_add_sandbox_fields.py similarity index 100% rename from smoothschedule/core/migrations/0008_add_sandbox_fields.py rename to smoothschedule/smoothschedule/identity/core/migrations/0008_add_sandbox_fields.py diff --git a/smoothschedule/core/migrations/0009_add_feature_limits.py b/smoothschedule/smoothschedule/identity/core/migrations/0009_add_feature_limits.py similarity index 100% rename from smoothschedule/core/migrations/0009_add_feature_limits.py rename to smoothschedule/smoothschedule/identity/core/migrations/0009_add_feature_limits.py diff --git a/smoothschedule/core/migrations/0010_add_oauth_credential_model.py b/smoothschedule/smoothschedule/identity/core/migrations/0010_add_oauth_credential_model.py similarity index 100% rename from smoothschedule/core/migrations/0010_add_oauth_credential_model.py rename to smoothschedule/smoothschedule/identity/core/migrations/0010_add_oauth_credential_model.py diff --git a/smoothschedule/core/migrations/0011_tenant_twilio_phone_number_and_more.py b/smoothschedule/smoothschedule/identity/core/migrations/0011_tenant_twilio_phone_number_and_more.py similarity index 100% rename from smoothschedule/core/migrations/0011_tenant_twilio_phone_number_and_more.py rename to smoothschedule/smoothschedule/identity/core/migrations/0011_tenant_twilio_phone_number_and_more.py diff --git a/smoothschedule/core/migrations/0012_tenant_can_use_sms_reminders.py b/smoothschedule/smoothschedule/identity/core/migrations/0012_tenant_can_use_sms_reminders.py similarity index 100% rename from smoothschedule/core/migrations/0012_tenant_can_use_sms_reminders.py rename to smoothschedule/smoothschedule/identity/core/migrations/0012_tenant_can_use_sms_reminders.py diff --git a/smoothschedule/core/migrations/0013_stripe_payment_fields.py b/smoothschedule/smoothschedule/identity/core/migrations/0013_stripe_payment_fields.py similarity index 100% rename from smoothschedule/core/migrations/0013_stripe_payment_fields.py rename to smoothschedule/smoothschedule/identity/core/migrations/0013_stripe_payment_fields.py diff --git a/smoothschedule/core/migrations/0014_tenant_can_export_data_tenant_subscription_plan.py b/smoothschedule/smoothschedule/identity/core/migrations/0014_tenant_can_export_data_tenant_subscription_plan.py similarity index 100% rename from smoothschedule/core/migrations/0014_tenant_can_export_data_tenant_subscription_plan.py rename to smoothschedule/smoothschedule/identity/core/migrations/0014_tenant_can_export_data_tenant_subscription_plan.py diff --git a/smoothschedule/core/migrations/0015_tenant_can_create_plugins_tenant_can_use_webhooks.py b/smoothschedule/smoothschedule/identity/core/migrations/0015_tenant_can_create_plugins_tenant_can_use_webhooks.py similarity index 100% rename from smoothschedule/core/migrations/0015_tenant_can_create_plugins_tenant_can_use_webhooks.py rename to smoothschedule/smoothschedule/identity/core/migrations/0015_tenant_can_create_plugins_tenant_can_use_webhooks.py diff --git a/smoothschedule/core/migrations/0016_tenant_can_use_calendar_sync.py b/smoothschedule/smoothschedule/identity/core/migrations/0016_tenant_can_use_calendar_sync.py similarity index 100% rename from smoothschedule/core/migrations/0016_tenant_can_use_calendar_sync.py rename to smoothschedule/smoothschedule/identity/core/migrations/0016_tenant_can_use_calendar_sync.py diff --git a/smoothschedule/core/migrations/0017_alter_tierlimit_feature_code_quotaoverage.py b/smoothschedule/smoothschedule/identity/core/migrations/0017_alter_tierlimit_feature_code_quotaoverage.py similarity index 100% rename from smoothschedule/core/migrations/0017_alter_tierlimit_feature_code_quotaoverage.py rename to smoothschedule/smoothschedule/identity/core/migrations/0017_alter_tierlimit_feature_code_quotaoverage.py diff --git a/smoothschedule/core/migrations/0018_add_stripe_customer_id.py b/smoothschedule/smoothschedule/identity/core/migrations/0018_add_stripe_customer_id.py similarity index 100% rename from smoothschedule/core/migrations/0018_add_stripe_customer_id.py rename to smoothschedule/smoothschedule/identity/core/migrations/0018_add_stripe_customer_id.py diff --git a/smoothschedule/core/migrations/0019_add_timezone_fields.py b/smoothschedule/smoothschedule/identity/core/migrations/0019_add_timezone_fields.py similarity index 100% rename from smoothschedule/core/migrations/0019_add_timezone_fields.py rename to smoothschedule/smoothschedule/identity/core/migrations/0019_add_timezone_fields.py diff --git a/smoothschedule/core/migrations/0020_booking_return_url.py b/smoothschedule/smoothschedule/identity/core/migrations/0020_booking_return_url.py similarity index 100% rename from smoothschedule/core/migrations/0020_booking_return_url.py rename to smoothschedule/smoothschedule/identity/core/migrations/0020_booking_return_url.py diff --git a/smoothschedule/core/migrations/0021_add_can_use_plugins.py b/smoothschedule/smoothschedule/identity/core/migrations/0021_add_can_use_plugins.py similarity index 100% rename from smoothschedule/core/migrations/0021_add_can_use_plugins.py rename to smoothschedule/smoothschedule/identity/core/migrations/0021_add_can_use_plugins.py diff --git a/smoothschedule/core/migrations/0022_add_can_use_tasks.py b/smoothschedule/smoothschedule/identity/core/migrations/0022_add_can_use_tasks.py similarity index 100% rename from smoothschedule/core/migrations/0022_add_can_use_tasks.py rename to smoothschedule/smoothschedule/identity/core/migrations/0022_add_can_use_tasks.py diff --git a/smoothschedule/schedule/management/commands/__init__.py b/smoothschedule/smoothschedule/identity/core/migrations/__init__.py similarity index 100% rename from smoothschedule/schedule/management/commands/__init__.py rename to smoothschedule/smoothschedule/identity/core/migrations/__init__.py diff --git a/smoothschedule/core/mixins.py b/smoothschedule/smoothschedule/identity/core/mixins.py similarity index 98% rename from smoothschedule/core/mixins.py rename to smoothschedule/smoothschedule/identity/core/mixins.py index e301884..d17e4e9 100644 --- a/smoothschedule/core/mixins.py +++ b/smoothschedule/smoothschedule/identity/core/mixins.py @@ -56,7 +56,7 @@ class DenyStaffWritePermission(BasePermission): return True # Check if user is staff - from smoothschedule.users.models import User + from smoothschedule.identity.users.models import User if request.user.is_authenticated and request.user.role == User.Role.TENANT_STAFF: # Check for per-user permission override permission_key = self._get_permission_key(view, 'write') @@ -107,7 +107,7 @@ class DenyStaffAllAccessPermission(BasePermission): message = "Staff members do not have access to this resource." def has_permission(self, request, view): - from smoothschedule.users.models import User + from smoothschedule.identity.users.models import User if request.user.is_authenticated and request.user.role == User.Role.TENANT_STAFF: # Check for per-user permission override permission_key = self._get_permission_key(view) @@ -159,7 +159,7 @@ class DenyStaffListPermission(BasePermission): message = "Staff members do not have access to this resource." def has_permission(self, request, view): - from smoothschedule.users.models import User + from smoothschedule.identity.users.models import User # Allow retrieve (detail view) for staff if view.action == 'retrieve': @@ -247,7 +247,7 @@ class TenantFilteredQuerySetMixin: # Optionally deny staff access at queryset level if self.deny_staff_queryset: - from smoothschedule.users.models import User + from smoothschedule.identity.users.models import User if user.role == User.Role.TENANT_STAFF: return queryset.none() @@ -436,7 +436,7 @@ class TenantAPIView: Usage: from rest_framework.views import APIView - from core.mixins import TenantAPIView + from smoothschedule.identity.core.mixins import TenantAPIView class MyView(TenantAPIView, APIView): permission_classes = [IsAuthenticated] diff --git a/smoothschedule/core/models.py b/smoothschedule/smoothschedule/identity/core/models.py similarity index 99% rename from smoothschedule/core/models.py rename to smoothschedule/smoothschedule/identity/core/models.py index 5065129..7ac1f65 100644 --- a/smoothschedule/core/models.py +++ b/smoothschedule/smoothschedule/identity/core/models.py @@ -372,8 +372,9 @@ class Tenant(TenantMixin): # - schema_name (unique, indexed) # - auto_create_schema # - auto_drop_schema - + class Meta: + app_label = 'core' ordering = ['name'] def save(self, *args, **kwargs): @@ -478,8 +479,9 @@ class Domain(DomainMixin): blank=True, help_text="When the custom domain was verified via DNS" ) - + class Meta: + app_label = 'core' ordering = ['domain'] def __str__(self): @@ -564,8 +566,9 @@ class PermissionGrant(models.Model): blank=True, help_text="Browser/client user agent" ) - + class Meta: + app_label = 'core' ordering = ['-granted_at'] indexes = [ models.Index(fields=['grantee', 'expires_at']), @@ -738,6 +741,7 @@ class OAuthCredential(models.Model): updated_at = models.DateTimeField(auto_now=True) class Meta: + app_label = 'core' ordering = ['-created_at'] indexes = [ models.Index(fields=['tenant', 'provider', 'purpose']), @@ -826,6 +830,7 @@ class TierLimit(models.Model): ) class Meta: + app_label = 'core' unique_together = ['tier', 'feature_code'] ordering = ['tier', 'feature_code'] @@ -946,6 +951,7 @@ class QuotaOverage(models.Model): ) class Meta: + app_label = 'core' ordering = ['-detected_at'] indexes = [ models.Index(fields=['tenant', 'status']), diff --git a/smoothschedule/core/oauth_service.py b/smoothschedule/smoothschedule/identity/core/oauth_service.py similarity index 100% rename from smoothschedule/core/oauth_service.py rename to smoothschedule/smoothschedule/identity/core/oauth_service.py diff --git a/smoothschedule/core/oauth_urls.py b/smoothschedule/smoothschedule/identity/core/oauth_urls.py similarity index 100% rename from smoothschedule/core/oauth_urls.py rename to smoothschedule/smoothschedule/identity/core/oauth_urls.py diff --git a/smoothschedule/core/oauth_views.py b/smoothschedule/smoothschedule/identity/core/oauth_views.py similarity index 99% rename from smoothschedule/core/oauth_views.py rename to smoothschedule/smoothschedule/identity/core/oauth_views.py index dfaab11..57e5604 100644 --- a/smoothschedule/core/oauth_views.py +++ b/smoothschedule/smoothschedule/identity/core/oauth_views.py @@ -19,7 +19,7 @@ from rest_framework.permissions import IsAuthenticated from rest_framework.permissions import AllowAny -from platform_admin.permissions import IsPlatformAdmin +from smoothschedule.platform.admin.permissions import IsPlatformAdmin from .models import OAuthCredential from .oauth_service import ( GoogleOAuthService, diff --git a/smoothschedule/core/permissions.py b/smoothschedule/smoothschedule/identity/core/permissions.py similarity index 98% rename from smoothschedule/core/permissions.py rename to smoothschedule/smoothschedule/identity/core/permissions.py index 6b4c96b..49eb216 100644 --- a/smoothschedule/core/permissions.py +++ b/smoothschedule/smoothschedule/identity/core/permissions.py @@ -33,7 +33,7 @@ def can_hijack(hijacker, hijacked): - Always validate tenant boundaries for tenant-scoped roles - Log all hijack attempts (success and failure) for audit """ - from smoothschedule.users.models import User + from smoothschedule.identity.users.models import User # Safety check: can't hijack yourself if hijacker.id == hijacked.id: @@ -113,7 +113,7 @@ def get_hijackable_users(hijacker): Returns: QuerySet: Users that can be hijacked by this user """ - from smoothschedule.users.models import User + from smoothschedule.identity.users.models import User # Start with all users except self qs = User.objects.exclude(id=hijacker.id) @@ -262,7 +262,7 @@ def HasQuota(feature_code): # Get the tier limit for this tenant try: - from core.models import TierLimit + from smoothschedule.identity.core.models import TierLimit limit = TierLimit.objects.get( tier=tenant.subscription_tier, feature_code=feature_code @@ -277,7 +277,7 @@ def HasQuota(feature_code): # Special handling for additional users (shared schema, exclude owner) if feature_code == 'MAX_ADDITIONAL_USERS': - from smoothschedule.users.models import User + from smoothschedule.identity.users.models import User # Count users in this tenant, excluding the owner and archived users current_count = User.objects.filter( tenant=tenant, diff --git a/smoothschedule/core/quota_service.py b/smoothschedule/smoothschedule/identity/core/quota_service.py similarity index 96% rename from smoothschedule/core/quota_service.py rename to smoothschedule/smoothschedule/identity/core/quota_service.py index ff66396..efda5a7 100644 --- a/smoothschedule/core/quota_service.py +++ b/smoothschedule/smoothschedule/identity/core/quota_service.py @@ -23,7 +23,7 @@ from django.template.loader import render_to_string from django.conf import settings from .models import Tenant, QuotaOverage, TierLimit -from smoothschedule.users.models import User +from smoothschedule.identity.users.models import User logger = logging.getLogger(__name__) @@ -38,7 +38,7 @@ class QuotaService: # Quota types and their corresponding models/counting logic QUOTA_CONFIG = { 'MAX_ADDITIONAL_USERS': { - 'model': 'smoothschedule.users.models.User', + 'model': 'smoothschedule.identity.users.models.User', 'display_name': 'additional team members', 'count_method': 'count_additional_users', }, @@ -82,22 +82,22 @@ class QuotaService: def count_resources(self) -> int: """Count active resources (excluding archived).""" - from schedule.models import Resource + from smoothschedule.scheduling.schedule.models import Resource return Resource.objects.filter(is_archived_by_quota=False).count() def count_services(self) -> int: """Count active services (excluding archived).""" - from schedule.models import Service + from smoothschedule.scheduling.schedule.models import Service return Service.objects.filter(is_archived_by_quota=False).count() def count_email_templates(self) -> int: """Count email templates.""" - from schedule.models import EmailTemplate + from smoothschedule.scheduling.schedule.models import EmailTemplate return EmailTemplate.objects.count() def count_automated_tasks(self) -> int: """Count automated tasks.""" - from schedule.models import ScheduledTask + from smoothschedule.scheduling.schedule.models import ScheduledTask return ScheduledTask.objects.count() # ========================================================================= @@ -363,7 +363,7 @@ class QuotaService: ) elif quota_type == 'MAX_RESOURCES': - from schedule.models import Resource + from smoothschedule.scheduling.schedule.models import Resource count = Resource.objects.filter( id__in=resource_ids, is_archived_by_quota=False @@ -373,7 +373,7 @@ class QuotaService: ) elif quota_type == 'MAX_SERVICES': - from schedule.models import Service + from smoothschedule.scheduling.schedule.models import Service count = Service.objects.filter( id__in=resource_ids, is_archived_by_quota=False @@ -422,13 +422,13 @@ class QuotaService: archived_by_quota_at=None ) elif quota_type == 'MAX_RESOURCES': - from schedule.models import Resource + from smoothschedule.scheduling.schedule.models import Resource Resource.objects.filter(id=resource_id).update( is_archived_by_quota=False, archived_by_quota_at=None ) elif quota_type == 'MAX_SERVICES': - from schedule.models import Service + from smoothschedule.scheduling.schedule.models import Service Service.objects.filter(id=resource_id).update( is_archived_by_quota=False, archived_by_quota_at=None @@ -488,7 +488,7 @@ class QuotaService: archived_ids.append(user.id) elif quota_type == 'MAX_RESOURCES': - from schedule.models import Resource + from smoothschedule.scheduling.schedule.models import Resource resources = Resource.objects.filter( is_archived_by_quota=False ).order_by('created_at')[:excess_count] @@ -500,7 +500,7 @@ class QuotaService: archived_ids.append(resource.id) elif quota_type == 'MAX_SERVICES': - from schedule.models import Service + from smoothschedule.scheduling.schedule.models import Service services = Service.objects.filter( is_archived_by_quota=False ).order_by('created_at')[:excess_count] diff --git a/smoothschedule/core/signals.py b/smoothschedule/smoothschedule/identity/core/signals.py similarity index 93% rename from smoothschedule/core/signals.py rename to smoothschedule/smoothschedule/identity/core/signals.py index 5123fcf..4d3feb1 100644 --- a/smoothschedule/core/signals.py +++ b/smoothschedule/smoothschedule/identity/core/signals.py @@ -17,7 +17,7 @@ def _seed_plugins_for_tenant(tenant_schema_name): Called after transaction commits to ensure schema tables exist. """ from django_tenants.utils import schema_context - from schedule.models import PluginTemplate + from smoothschedule.scheduling.schedule.models import PluginTemplate from django.utils import timezone logger.info(f"Seeding platform plugins for new tenant: {tenant_schema_name}") @@ -25,7 +25,7 @@ def _seed_plugins_for_tenant(tenant_schema_name): try: with schema_context(tenant_schema_name): # Import the plugin definitions from the seed command - from schedule.management.commands.seed_platform_plugins import get_platform_plugins + from smoothschedule.scheduling.schedule.management.commands.seed_platform_plugins import get_platform_plugins plugins_data = get_platform_plugins() created_count = 0 diff --git a/smoothschedule/core/tasks.py b/smoothschedule/smoothschedule/identity/core/tasks.py similarity index 100% rename from smoothschedule/core/tasks.py rename to smoothschedule/smoothschedule/identity/core/tasks.py diff --git a/smoothschedule/schedule/migrations/__init__.py b/smoothschedule/smoothschedule/identity/users/__init__.py similarity index 100% rename from smoothschedule/schedule/migrations/__init__.py rename to smoothschedule/smoothschedule/identity/users/__init__.py diff --git a/smoothschedule/smoothschedule/users/adapters.py b/smoothschedule/smoothschedule/identity/users/adapters.py similarity index 96% rename from smoothschedule/smoothschedule/users/adapters.py rename to smoothschedule/smoothschedule/identity/users/adapters.py index a420a04..95837c4 100644 --- a/smoothschedule/smoothschedule/users/adapters.py +++ b/smoothschedule/smoothschedule/identity/users/adapters.py @@ -10,7 +10,7 @@ if typing.TYPE_CHECKING: from allauth.socialaccount.models import SocialLogin from django.http import HttpRequest - from smoothschedule.users.models import User + from smoothschedule.identity.users.models import User class AccountAdapter(DefaultAccountAdapter): diff --git a/smoothschedule/smoothschedule/users/admin.py b/smoothschedule/smoothschedule/identity/users/admin.py similarity index 100% rename from smoothschedule/smoothschedule/users/admin.py rename to smoothschedule/smoothschedule/identity/users/admin.py diff --git a/smoothschedule/smoothschedule/comms_credits/__init__.py b/smoothschedule/smoothschedule/identity/users/api/__init__.py similarity index 100% rename from smoothschedule/smoothschedule/comms_credits/__init__.py rename to smoothschedule/smoothschedule/identity/users/api/__init__.py diff --git a/smoothschedule/smoothschedule/users/api/serializers.py b/smoothschedule/smoothschedule/identity/users/api/serializers.py similarity index 84% rename from smoothschedule/smoothschedule/users/api/serializers.py rename to smoothschedule/smoothschedule/identity/users/api/serializers.py index dcdb9cd..c38d76a 100644 --- a/smoothschedule/smoothschedule/users/api/serializers.py +++ b/smoothschedule/smoothschedule/identity/users/api/serializers.py @@ -1,6 +1,6 @@ from rest_framework import serializers -from smoothschedule.users.models import User +from smoothschedule.identity.users.models import User class UserSerializer(serializers.ModelSerializer[User]): diff --git a/smoothschedule/smoothschedule/users/api/views.py b/smoothschedule/smoothschedule/identity/users/api/views.py similarity index 94% rename from smoothschedule/smoothschedule/users/api/views.py rename to smoothschedule/smoothschedule/identity/users/api/views.py index 654e802..470a732 100644 --- a/smoothschedule/smoothschedule/users/api/views.py +++ b/smoothschedule/smoothschedule/identity/users/api/views.py @@ -6,7 +6,7 @@ from rest_framework.mixins import UpdateModelMixin from rest_framework.response import Response from rest_framework.viewsets import GenericViewSet -from smoothschedule.users.models import User +from smoothschedule.identity.users.models import User from .serializers import UserSerializer diff --git a/smoothschedule/smoothschedule/users/api_views.py b/smoothschedule/smoothschedule/identity/users/api_views.py similarity index 99% rename from smoothschedule/smoothschedule/users/api_views.py rename to smoothschedule/smoothschedule/identity/users/api_views.py index 5676eed..0c53d21 100644 --- a/smoothschedule/smoothschedule/users/api_views.py +++ b/smoothschedule/smoothschedule/identity/users/api_views.py @@ -15,10 +15,10 @@ from rest_framework.authtoken.models import Token from .models import User, EmailVerificationToken, StaffInvitation, TrustedDevice from .mfa_services import mfa_manager -from core.permissions import can_hijack +from smoothschedule.identity.core.permissions import can_hijack from rest_framework import serializers -from schedule.models import Resource, ResourceType -from core.models import Tenant, Domain +from smoothschedule.scheduling.schedule.models import Resource, ResourceType +from smoothschedule.identity.core.models import Tenant, Domain from django_tenants.utils import schema_context @@ -132,7 +132,7 @@ def current_user_view(request): # Check for active quota overages (for owners and managers) if user.role in [User.Role.TENANT_OWNER, User.Role.TENANT_MANAGER]: - from core.quota_service import QuotaService + from smoothschedule.identity.core.quota_service import QuotaService try: service = QuotaService(user.tenant) quota_overages = service.get_active_overages() diff --git a/smoothschedule/smoothschedule/users/apps.py b/smoothschedule/smoothschedule/identity/users/apps.py similarity index 62% rename from smoothschedule/smoothschedule/users/apps.py rename to smoothschedule/smoothschedule/identity/users/apps.py index 3a8404a..9267e40 100644 --- a/smoothschedule/smoothschedule/users/apps.py +++ b/smoothschedule/smoothschedule/identity/users/apps.py @@ -5,9 +5,10 @@ from django.utils.translation import gettext_lazy as _ class UsersConfig(AppConfig): - name = "smoothschedule.users" + name = "smoothschedule.identity.users" + label = "users" verbose_name = _("Users") def ready(self): with contextlib.suppress(ImportError): - import smoothschedule.users.signals # noqa: F401, PLC0415 + import smoothschedule.identity.users.signals # noqa: F401, PLC0415 diff --git a/smoothschedule/smoothschedule/users/context_processors.py b/smoothschedule/smoothschedule/identity/users/context_processors.py similarity index 100% rename from smoothschedule/smoothschedule/users/context_processors.py rename to smoothschedule/smoothschedule/identity/users/context_processors.py diff --git a/smoothschedule/smoothschedule/users/forms.py b/smoothschedule/smoothschedule/identity/users/forms.py similarity index 100% rename from smoothschedule/smoothschedule/users/forms.py rename to smoothschedule/smoothschedule/identity/users/forms.py diff --git a/smoothschedule/smoothschedule/comms_credits/migrations/__init__.py b/smoothschedule/smoothschedule/identity/users/management/__init__.py similarity index 100% rename from smoothschedule/smoothschedule/comms_credits/migrations/__init__.py rename to smoothschedule/smoothschedule/identity/users/management/__init__.py diff --git a/smoothschedule/smoothschedule/field_mobile/migrations/__init__.py b/smoothschedule/smoothschedule/identity/users/management/commands/__init__.py similarity index 100% rename from smoothschedule/smoothschedule/field_mobile/migrations/__init__.py rename to smoothschedule/smoothschedule/identity/users/management/commands/__init__.py diff --git a/smoothschedule/smoothschedule/users/management/commands/create_platform_admin.py b/smoothschedule/smoothschedule/identity/users/management/commands/create_platform_admin.py similarity index 96% rename from smoothschedule/smoothschedule/users/management/commands/create_platform_admin.py rename to smoothschedule/smoothschedule/identity/users/management/commands/create_platform_admin.py index 2286b8f..37a5bd9 100644 --- a/smoothschedule/smoothschedule/users/management/commands/create_platform_admin.py +++ b/smoothschedule/smoothschedule/identity/users/management/commands/create_platform_admin.py @@ -2,7 +2,7 @@ from django.core.management.base import BaseCommand from rest_framework.authtoken.models import Token -from smoothschedule.users.models import User +from smoothschedule.identity.users.models import User class Command(BaseCommand): diff --git a/smoothschedule/smoothschedule/users/management/commands/create_test_users.py b/smoothschedule/smoothschedule/identity/users/management/commands/create_test_users.py similarity index 97% rename from smoothschedule/smoothschedule/users/management/commands/create_test_users.py rename to smoothschedule/smoothschedule/identity/users/management/commands/create_test_users.py index 95c1ef7..c53a448 100644 --- a/smoothschedule/smoothschedule/users/management/commands/create_test_users.py +++ b/smoothschedule/smoothschedule/identity/users/management/commands/create_test_users.py @@ -2,8 +2,8 @@ from django.core.management.base import BaseCommand from rest_framework.authtoken.models import Token -from core.models import Tenant -from smoothschedule.users.models import User +from smoothschedule.identity.core.models import Tenant +from smoothschedule.identity.users.models import User class Command(BaseCommand): diff --git a/smoothschedule/smoothschedule/users/mfa_api_views.py b/smoothschedule/smoothschedule/identity/users/mfa_api_views.py similarity index 100% rename from smoothschedule/smoothschedule/users/mfa_api_views.py rename to smoothschedule/smoothschedule/identity/users/mfa_api_views.py diff --git a/smoothschedule/smoothschedule/users/mfa_services.py b/smoothschedule/smoothschedule/identity/users/mfa_services.py similarity index 100% rename from smoothschedule/smoothschedule/users/mfa_services.py rename to smoothschedule/smoothschedule/identity/users/mfa_services.py diff --git a/smoothschedule/smoothschedule/users/migrations/0001_initial.py b/smoothschedule/smoothschedule/identity/users/migrations/0001_initial.py similarity index 99% rename from smoothschedule/smoothschedule/users/migrations/0001_initial.py rename to smoothschedule/smoothschedule/identity/users/migrations/0001_initial.py index 9f437b8..0bcb1a6 100644 --- a/smoothschedule/smoothschedule/users/migrations/0001_initial.py +++ b/smoothschedule/smoothschedule/identity/users/migrations/0001_initial.py @@ -4,7 +4,7 @@ import django.utils.timezone from django.db import migrations from django.db import models -import smoothschedule.users.models +import smoothschedule.identity.users.models class Migration(migrations.Migration): diff --git a/smoothschedule/smoothschedule/users/migrations/0002_alter_user_options_remove_user_name_user_created_at_and_more.py b/smoothschedule/smoothschedule/identity/users/migrations/0002_alter_user_options_remove_user_name_user_created_at_and_more.py similarity index 100% rename from smoothschedule/smoothschedule/users/migrations/0002_alter_user_options_remove_user_name_user_created_at_and_more.py rename to smoothschedule/smoothschedule/identity/users/migrations/0002_alter_user_options_remove_user_name_user_created_at_and_more.py diff --git a/smoothschedule/smoothschedule/users/migrations/0003_add_email_verification.py b/smoothschedule/smoothschedule/identity/users/migrations/0003_add_email_verification.py similarity index 100% rename from smoothschedule/smoothschedule/users/migrations/0003_add_email_verification.py rename to smoothschedule/smoothschedule/identity/users/migrations/0003_add_email_verification.py diff --git a/smoothschedule/smoothschedule/users/migrations/0004_add_staff_invitation.py b/smoothschedule/smoothschedule/identity/users/migrations/0004_add_staff_invitation.py similarity index 100% rename from smoothschedule/smoothschedule/users/migrations/0004_add_staff_invitation.py rename to smoothschedule/smoothschedule/identity/users/migrations/0004_add_staff_invitation.py diff --git a/smoothschedule/smoothschedule/users/migrations/0005_add_bookable_and_permissions_to_invitation.py b/smoothschedule/smoothschedule/identity/users/migrations/0005_add_bookable_and_permissions_to_invitation.py similarity index 100% rename from smoothschedule/smoothschedule/users/migrations/0005_add_bookable_and_permissions_to_invitation.py rename to smoothschedule/smoothschedule/identity/users/migrations/0005_add_bookable_and_permissions_to_invitation.py diff --git a/smoothschedule/smoothschedule/users/migrations/0006_add_permissions_to_user.py b/smoothschedule/smoothschedule/identity/users/migrations/0006_add_permissions_to_user.py similarity index 100% rename from smoothschedule/smoothschedule/users/migrations/0006_add_permissions_to_user.py rename to smoothschedule/smoothschedule/identity/users/migrations/0006_add_permissions_to_user.py diff --git a/smoothschedule/smoothschedule/users/migrations/0007_add_is_sandbox_to_user.py b/smoothschedule/smoothschedule/identity/users/migrations/0007_add_is_sandbox_to_user.py similarity index 100% rename from smoothschedule/smoothschedule/users/migrations/0007_add_is_sandbox_to_user.py rename to smoothschedule/smoothschedule/identity/users/migrations/0007_add_is_sandbox_to_user.py diff --git a/smoothschedule/smoothschedule/users/migrations/0008_add_mfa_fields.py b/smoothschedule/smoothschedule/identity/users/migrations/0008_add_mfa_fields.py similarity index 100% rename from smoothschedule/smoothschedule/users/migrations/0008_add_mfa_fields.py rename to smoothschedule/smoothschedule/identity/users/migrations/0008_add_mfa_fields.py diff --git a/smoothschedule/smoothschedule/users/migrations/0009_user_archived_by_quota_at_user_is_archived_by_quota.py b/smoothschedule/smoothschedule/identity/users/migrations/0009_user_archived_by_quota_at_user_is_archived_by_quota.py similarity index 100% rename from smoothschedule/smoothschedule/users/migrations/0009_user_archived_by_quota_at_user_is_archived_by_quota.py rename to smoothschedule/smoothschedule/identity/users/migrations/0009_user_archived_by_quota_at_user_is_archived_by_quota.py diff --git a/smoothschedule/smoothschedule/users/migrations/0010_add_stripe_customer_fields.py b/smoothschedule/smoothschedule/identity/users/migrations/0010_add_stripe_customer_fields.py similarity index 100% rename from smoothschedule/smoothschedule/users/migrations/0010_add_stripe_customer_fields.py rename to smoothschedule/smoothschedule/identity/users/migrations/0010_add_stripe_customer_fields.py diff --git a/smoothschedule/smoothschedule/public_api/migrations/__init__.py b/smoothschedule/smoothschedule/identity/users/migrations/__init__.py similarity index 100% rename from smoothschedule/smoothschedule/public_api/migrations/__init__.py rename to smoothschedule/smoothschedule/identity/users/migrations/__init__.py diff --git a/smoothschedule/smoothschedule/users/models.py b/smoothschedule/smoothschedule/identity/users/models.py similarity index 99% rename from smoothschedule/smoothschedule/users/models.py rename to smoothschedule/smoothschedule/identity/users/models.py index 6d9d5f2..cdc9ee7 100644 --- a/smoothschedule/smoothschedule/users/models.py +++ b/smoothschedule/smoothschedule/identity/users/models.py @@ -147,8 +147,9 @@ class User(AbstractUser): created_at = models.DateTimeField(auto_now_add=True) updated_at = models.DateTimeField(auto_now=True) last_login_ip = models.GenericIPAddressField(null=True, blank=True) - + class Meta: + app_label = 'users' ordering = ['email'] indexes = [ models.Index(fields=['role', 'tenant']), @@ -287,7 +288,7 @@ class User(AbstractUser): Platform users can access all tenants. Tenant users can only access their own tenant. """ - from core.models import Tenant + from smoothschedule.identity.core.models import Tenant if self.is_platform_user(): return Tenant.objects.all() @@ -331,6 +332,7 @@ class EmailVerificationToken(models.Model): used = models.BooleanField(default=False) class Meta: + app_label = 'users' ordering = ['-created_at'] def save(self, *args, **kwargs): @@ -376,6 +378,7 @@ class MFAVerificationCode(models.Model): attempts = models.IntegerField(default=0, help_text="Number of failed verification attempts") class Meta: + app_label = 'users' ordering = ['-created_at'] indexes = [ models.Index(fields=['user', 'purpose', 'used']), @@ -443,6 +446,7 @@ class TrustedDevice(models.Model): expires_at = models.DateTimeField() class Meta: + app_label = 'users' ordering = ['-last_used_at'] unique_together = ['user', 'device_hash'] indexes = [ @@ -567,6 +571,7 @@ class StaffInvitation(models.Model): ) class Meta: + app_label = 'users' ordering = ['-created_at'] indexes = [ models.Index(fields=['token']), diff --git a/smoothschedule/smoothschedule/users/tasks.py b/smoothschedule/smoothschedule/identity/users/tasks.py similarity index 100% rename from smoothschedule/smoothschedule/users/tasks.py rename to smoothschedule/smoothschedule/identity/users/tasks.py diff --git a/smoothschedule/smoothschedule/schedule/management/__init__.py b/smoothschedule/smoothschedule/identity/users/tests/__init__.py similarity index 100% rename from smoothschedule/smoothschedule/schedule/management/__init__.py rename to smoothschedule/smoothschedule/identity/users/tests/__init__.py diff --git a/smoothschedule/smoothschedule/schedule/management/commands/__init__.py b/smoothschedule/smoothschedule/identity/users/tests/api/__init__.py similarity index 100% rename from smoothschedule/smoothschedule/schedule/management/commands/__init__.py rename to smoothschedule/smoothschedule/identity/users/tests/api/__init__.py diff --git a/smoothschedule/smoothschedule/users/tests/api/test_openapi.py b/smoothschedule/smoothschedule/identity/users/tests/api/test_openapi.py similarity index 100% rename from smoothschedule/smoothschedule/users/tests/api/test_openapi.py rename to smoothschedule/smoothschedule/identity/users/tests/api/test_openapi.py diff --git a/smoothschedule/smoothschedule/users/tests/api/test_urls.py b/smoothschedule/smoothschedule/identity/users/tests/api/test_urls.py similarity index 91% rename from smoothschedule/smoothschedule/users/tests/api/test_urls.py rename to smoothschedule/smoothschedule/identity/users/tests/api/test_urls.py index f94df1f..67c1256 100644 --- a/smoothschedule/smoothschedule/users/tests/api/test_urls.py +++ b/smoothschedule/smoothschedule/identity/users/tests/api/test_urls.py @@ -1,7 +1,7 @@ from django.urls import resolve from django.urls import reverse -from smoothschedule.users.models import User +from smoothschedule.identity.users.models import User def test_user_detail(user: User): diff --git a/smoothschedule/smoothschedule/users/tests/api/test_views.py b/smoothschedule/smoothschedule/identity/users/tests/api/test_views.py similarity index 88% rename from smoothschedule/smoothschedule/users/tests/api/test_views.py rename to smoothschedule/smoothschedule/identity/users/tests/api/test_views.py index e478e32..a45cb37 100644 --- a/smoothschedule/smoothschedule/users/tests/api/test_views.py +++ b/smoothschedule/smoothschedule/identity/users/tests/api/test_views.py @@ -1,8 +1,8 @@ import pytest from rest_framework.test import APIRequestFactory -from smoothschedule.users.api.views import UserViewSet -from smoothschedule.users.models import User +from smoothschedule.identity.users.api.views import UserViewSet +from smoothschedule.identity.users.models import User class TestUserViewSet: diff --git a/smoothschedule/smoothschedule/users/tests/factories.py b/smoothschedule/smoothschedule/identity/users/tests/factories.py similarity index 95% rename from smoothschedule/smoothschedule/users/tests/factories.py rename to smoothschedule/smoothschedule/identity/users/tests/factories.py index b3b8044..072e5ce 100644 --- a/smoothschedule/smoothschedule/users/tests/factories.py +++ b/smoothschedule/smoothschedule/identity/users/tests/factories.py @@ -5,7 +5,7 @@ from factory import Faker from factory import post_generation from factory.django import DjangoModelFactory -from smoothschedule.users.models import User +from smoothschedule.identity.users.models import User class UserFactory(DjangoModelFactory[User]): diff --git a/smoothschedule/smoothschedule/users/tests/test_admin.py b/smoothschedule/smoothschedule/identity/users/tests/test_admin.py similarity index 94% rename from smoothschedule/smoothschedule/users/tests/test_admin.py rename to smoothschedule/smoothschedule/identity/users/tests/test_admin.py index c9bf6df..cfbc35f 100644 --- a/smoothschedule/smoothschedule/users/tests/test_admin.py +++ b/smoothschedule/smoothschedule/identity/users/tests/test_admin.py @@ -8,7 +8,7 @@ from django.contrib.auth.models import AnonymousUser from django.urls import reverse from pytest_django.asserts import assertRedirects -from smoothschedule.users.models import User +from smoothschedule.identity.users.models import User class TestUserAdmin: @@ -48,7 +48,7 @@ class TestUserAdmin: def _force_allauth(self, settings): settings.DJANGO_ADMIN_FORCE_ALLAUTH = True # Reload the admin module to apply the setting change - import smoothschedule.users.admin as users_admin # noqa: PLC0415 + import smoothschedule.identity.users.admin as users_admin # noqa: PLC0415 with contextlib.suppress(admin.sites.AlreadyRegistered): # type: ignore[attr-defined] reload(users_admin) diff --git a/smoothschedule/smoothschedule/users/tests/test_forms.py b/smoothschedule/smoothschedule/identity/users/tests/test_forms.py similarity index 89% rename from smoothschedule/smoothschedule/users/tests/test_forms.py rename to smoothschedule/smoothschedule/identity/users/tests/test_forms.py index 5d39352..4724abd 100644 --- a/smoothschedule/smoothschedule/users/tests/test_forms.py +++ b/smoothschedule/smoothschedule/identity/users/tests/test_forms.py @@ -2,8 +2,8 @@ from django.utils.translation import gettext_lazy as _ -from smoothschedule.users.forms import UserAdminCreationForm -from smoothschedule.users.models import User +from smoothschedule.identity.users.forms import UserAdminCreationForm +from smoothschedule.identity.users.models import User class TestUserAdminCreationForm: diff --git a/smoothschedule/smoothschedule/users/tests/test_models.py b/smoothschedule/smoothschedule/identity/users/tests/test_models.py similarity index 67% rename from smoothschedule/smoothschedule/users/tests/test_models.py rename to smoothschedule/smoothschedule/identity/users/tests/test_models.py index b16aed6..3aecd48 100644 --- a/smoothschedule/smoothschedule/users/tests/test_models.py +++ b/smoothschedule/smoothschedule/identity/users/tests/test_models.py @@ -1,4 +1,4 @@ -from smoothschedule.users.models import User +from smoothschedule.identity.users.models import User def test_user_get_absolute_url(user: User): diff --git a/smoothschedule/smoothschedule/users/tests/test_tasks.py b/smoothschedule/smoothschedule/identity/users/tests/test_tasks.py similarity index 76% rename from smoothschedule/smoothschedule/users/tests/test_tasks.py rename to smoothschedule/smoothschedule/identity/users/tests/test_tasks.py index cb3f0b2..90394a8 100644 --- a/smoothschedule/smoothschedule/users/tests/test_tasks.py +++ b/smoothschedule/smoothschedule/identity/users/tests/test_tasks.py @@ -1,8 +1,8 @@ import pytest from celery.result import EagerResult -from smoothschedule.users.tasks import get_users_count -from smoothschedule.users.tests.factories import UserFactory +from smoothschedule.identity.users.tasks import get_users_count +from smoothschedule.identity.users.tests.factories import UserFactory pytestmark = pytest.mark.django_db diff --git a/smoothschedule/smoothschedule/users/tests/test_urls.py b/smoothschedule/smoothschedule/identity/users/tests/test_urls.py similarity index 91% rename from smoothschedule/smoothschedule/users/tests/test_urls.py rename to smoothschedule/smoothschedule/identity/users/tests/test_urls.py index 7a63af6..f4b5727 100644 --- a/smoothschedule/smoothschedule/users/tests/test_urls.py +++ b/smoothschedule/smoothschedule/identity/users/tests/test_urls.py @@ -1,7 +1,7 @@ from django.urls import resolve from django.urls import reverse -from smoothschedule.users.models import User +from smoothschedule.identity.users.models import User def test_detail(user: User): diff --git a/smoothschedule/smoothschedule/users/tests/test_views.py b/smoothschedule/smoothschedule/identity/users/tests/test_views.py similarity index 89% rename from smoothschedule/smoothschedule/users/tests/test_views.py rename to smoothschedule/smoothschedule/identity/users/tests/test_views.py index c5470cb..3ac4897 100644 --- a/smoothschedule/smoothschedule/users/tests/test_views.py +++ b/smoothschedule/smoothschedule/identity/users/tests/test_views.py @@ -12,12 +12,12 @@ from django.test import RequestFactory from django.urls import reverse from django.utils.translation import gettext_lazy as _ -from smoothschedule.users.forms import UserAdminChangeForm -from smoothschedule.users.models import User -from smoothschedule.users.tests.factories import UserFactory -from smoothschedule.users.views import UserRedirectView -from smoothschedule.users.views import UserUpdateView -from smoothschedule.users.views import user_detail_view +from smoothschedule.identity.users.forms import UserAdminChangeForm +from smoothschedule.identity.users.models import User +from smoothschedule.identity.users.tests.factories import UserFactory +from smoothschedule.identity.users.views import UserRedirectView +from smoothschedule.identity.users.views import UserUpdateView +from smoothschedule.identity.users.views import user_detail_view pytestmark = pytest.mark.django_db diff --git a/smoothschedule/smoothschedule/users/urls.py b/smoothschedule/smoothschedule/identity/users/urls.py similarity index 100% rename from smoothschedule/smoothschedule/users/urls.py rename to smoothschedule/smoothschedule/identity/users/urls.py diff --git a/smoothschedule/smoothschedule/users/views.py b/smoothschedule/smoothschedule/identity/users/views.py similarity index 96% rename from smoothschedule/smoothschedule/users/views.py rename to smoothschedule/smoothschedule/identity/users/views.py index 989659a..1cf8284 100644 --- a/smoothschedule/smoothschedule/users/views.py +++ b/smoothschedule/smoothschedule/identity/users/views.py @@ -7,7 +7,7 @@ from django.views.generic import DetailView from django.views.generic import RedirectView from django.views.generic import UpdateView -from smoothschedule.users.models import User +from smoothschedule.identity.users.models import User class UserDetailView(LoginRequiredMixin, DetailView): diff --git a/smoothschedule/smoothschedule/users/__init__.py b/smoothschedule/smoothschedule/platform/__init__.py similarity index 100% rename from smoothschedule/smoothschedule/users/__init__.py rename to smoothschedule/smoothschedule/platform/__init__.py diff --git a/smoothschedule/platform_admin/__init__.py b/smoothschedule/smoothschedule/platform/admin/__init__.py similarity index 100% rename from smoothschedule/platform_admin/__init__.py rename to smoothschedule/smoothschedule/platform/admin/__init__.py diff --git a/smoothschedule/platform_admin/apps.py b/smoothschedule/smoothschedule/platform/admin/apps.py similarity index 70% rename from smoothschedule/platform_admin/apps.py rename to smoothschedule/smoothschedule/platform/admin/apps.py index 8a2d18b..0d2d375 100644 --- a/smoothschedule/platform_admin/apps.py +++ b/smoothschedule/smoothschedule/platform/admin/apps.py @@ -3,7 +3,8 @@ from django.apps import AppConfig class PlatformAdminConfig(AppConfig): default_auto_field = 'django.db.models.BigAutoField' - name = 'platform_admin' + name = 'smoothschedule.platform.admin' + label = 'platform_admin' # Keep old label for migration compatibility verbose_name = 'Platform Management' def ready(self): diff --git a/smoothschedule/platform_admin/mail_server.py b/smoothschedule/smoothschedule/platform/admin/mail_server.py similarity index 100% rename from smoothschedule/platform_admin/mail_server.py rename to smoothschedule/smoothschedule/platform/admin/mail_server.py diff --git a/smoothschedule/smoothschedule/users/api/__init__.py b/smoothschedule/smoothschedule/platform/admin/management/__init__.py similarity index 100% rename from smoothschedule/smoothschedule/users/api/__init__.py rename to smoothschedule/smoothschedule/platform/admin/management/__init__.py diff --git a/smoothschedule/smoothschedule/users/management/__init__.py b/smoothschedule/smoothschedule/platform/admin/management/commands/__init__.py similarity index 100% rename from smoothschedule/smoothschedule/users/management/__init__.py rename to smoothschedule/smoothschedule/platform/admin/management/commands/__init__.py diff --git a/smoothschedule/platform_admin/management/commands/seed_subscription_plans.py b/smoothschedule/smoothschedule/platform/admin/management/commands/seed_subscription_plans.py similarity index 99% rename from smoothschedule/platform_admin/management/commands/seed_subscription_plans.py rename to smoothschedule/smoothschedule/platform/admin/management/commands/seed_subscription_plans.py index dbde021..5283c31 100644 --- a/smoothschedule/platform_admin/management/commands/seed_subscription_plans.py +++ b/smoothschedule/smoothschedule/platform/admin/management/commands/seed_subscription_plans.py @@ -7,7 +7,7 @@ Usage: """ from django.core.management.base import BaseCommand -from platform_admin.models import SubscriptionPlan +from smoothschedule.platform.admin.models import SubscriptionPlan class Command(BaseCommand): diff --git a/smoothschedule/platform_admin/migrations/0001_initial.py b/smoothschedule/smoothschedule/platform/admin/migrations/0001_initial.py similarity index 100% rename from smoothschedule/platform_admin/migrations/0001_initial.py rename to smoothschedule/smoothschedule/platform/admin/migrations/0001_initial.py diff --git a/smoothschedule/platform_admin/migrations/0002_add_limits_field.py b/smoothschedule/smoothschedule/platform/admin/migrations/0002_add_limits_field.py similarity index 100% rename from smoothschedule/platform_admin/migrations/0002_add_limits_field.py rename to smoothschedule/smoothschedule/platform/admin/migrations/0002_add_limits_field.py diff --git a/smoothschedule/platform_admin/migrations/0003_add_platform_settings.py b/smoothschedule/smoothschedule/platform/admin/migrations/0003_add_platform_settings.py similarity index 100% rename from smoothschedule/platform_admin/migrations/0003_add_platform_settings.py rename to smoothschedule/smoothschedule/platform/admin/migrations/0003_add_platform_settings.py diff --git a/smoothschedule/platform_admin/migrations/0004_subscriptionplan.py b/smoothschedule/smoothschedule/platform/admin/migrations/0004_subscriptionplan.py similarity index 100% rename from smoothschedule/platform_admin/migrations/0004_subscriptionplan.py rename to smoothschedule/smoothschedule/platform/admin/migrations/0004_subscriptionplan.py diff --git a/smoothschedule/platform_admin/migrations/0005_subscriptionplan_limits_subscriptionplan_permissions.py b/smoothschedule/smoothschedule/platform/admin/migrations/0005_subscriptionplan_limits_subscriptionplan_permissions.py similarity index 100% rename from smoothschedule/platform_admin/migrations/0005_subscriptionplan_limits_subscriptionplan_permissions.py rename to smoothschedule/smoothschedule/platform/admin/migrations/0005_subscriptionplan_limits_subscriptionplan_permissions.py diff --git a/smoothschedule/platform_admin/migrations/0006_subscriptionplan_is_most_popular_and_more.py b/smoothschedule/smoothschedule/platform/admin/migrations/0006_subscriptionplan_is_most_popular_and_more.py similarity index 100% rename from smoothschedule/platform_admin/migrations/0006_subscriptionplan_is_most_popular_and_more.py rename to smoothschedule/smoothschedule/platform/admin/migrations/0006_subscriptionplan_is_most_popular_and_more.py diff --git a/smoothschedule/platform_admin/migrations/0007_platformemailaddress.py b/smoothschedule/smoothschedule/platform/admin/migrations/0007_platformemailaddress.py similarity index 100% rename from smoothschedule/platform_admin/migrations/0007_platformemailaddress.py rename to smoothschedule/smoothschedule/platform/admin/migrations/0007_platformemailaddress.py diff --git a/smoothschedule/platform_admin/migrations/0008_add_sender_name_and_assigned_user.py b/smoothschedule/smoothschedule/platform/admin/migrations/0008_add_sender_name_and_assigned_user.py similarity index 100% rename from smoothschedule/platform_admin/migrations/0008_add_sender_name_and_assigned_user.py rename to smoothschedule/smoothschedule/platform/admin/migrations/0008_add_sender_name_and_assigned_user.py diff --git a/smoothschedule/platform_admin/migrations/0009_add_email_check_interval.py b/smoothschedule/smoothschedule/platform/admin/migrations/0009_add_email_check_interval.py similarity index 100% rename from smoothschedule/platform_admin/migrations/0009_add_email_check_interval.py rename to smoothschedule/smoothschedule/platform/admin/migrations/0009_add_email_check_interval.py diff --git a/smoothschedule/platform_admin/migrations/0010_subscriptionplan_default_auto_reload_amount_cents_and_more.py b/smoothschedule/smoothschedule/platform/admin/migrations/0010_subscriptionplan_default_auto_reload_amount_cents_and_more.py similarity index 100% rename from smoothschedule/platform_admin/migrations/0010_subscriptionplan_default_auto_reload_amount_cents_and_more.py rename to smoothschedule/smoothschedule/platform/admin/migrations/0010_subscriptionplan_default_auto_reload_amount_cents_and_more.py diff --git a/smoothschedule/platform_admin/migrations/0011_update_subscription_plan_business_tier.py b/smoothschedule/smoothschedule/platform/admin/migrations/0011_update_subscription_plan_business_tier.py similarity index 100% rename from smoothschedule/platform_admin/migrations/0011_update_subscription_plan_business_tier.py rename to smoothschedule/smoothschedule/platform/admin/migrations/0011_update_subscription_plan_business_tier.py diff --git a/smoothschedule/platform_admin/migrations/0012_add_contracts_enabled.py b/smoothschedule/smoothschedule/platform/admin/migrations/0012_add_contracts_enabled.py similarity index 100% rename from smoothschedule/platform_admin/migrations/0012_add_contracts_enabled.py rename to smoothschedule/smoothschedule/platform/admin/migrations/0012_add_contracts_enabled.py diff --git a/smoothschedule/smoothschedule/users/management/commands/__init__.py b/smoothschedule/smoothschedule/platform/admin/migrations/__init__.py similarity index 100% rename from smoothschedule/smoothschedule/users/management/commands/__init__.py rename to smoothschedule/smoothschedule/platform/admin/migrations/__init__.py diff --git a/smoothschedule/platform_admin/models.py b/smoothschedule/smoothschedule/platform/admin/models.py similarity index 100% rename from smoothschedule/platform_admin/models.py rename to smoothschedule/smoothschedule/platform/admin/models.py diff --git a/smoothschedule/platform_admin/permissions.py b/smoothschedule/smoothschedule/platform/admin/permissions.py similarity index 95% rename from smoothschedule/platform_admin/permissions.py rename to smoothschedule/smoothschedule/platform/admin/permissions.py index 7277c2e..9c5b75d 100644 --- a/smoothschedule/platform_admin/permissions.py +++ b/smoothschedule/smoothschedule/platform/admin/permissions.py @@ -3,7 +3,7 @@ Platform Permissions Custom permission classes for platform-level operations """ from rest_framework import permissions -from smoothschedule.users.models import User +from smoothschedule.identity.users.models import User class IsPlatformAdmin(permissions.BasePermission): diff --git a/smoothschedule/platform_admin/serializers.py b/smoothschedule/smoothschedule/platform/admin/serializers.py similarity index 99% rename from smoothschedule/platform_admin/serializers.py rename to smoothschedule/smoothschedule/platform/admin/serializers.py index 9efdc30..b17380d 100644 --- a/smoothschedule/platform_admin/serializers.py +++ b/smoothschedule/smoothschedule/platform/admin/serializers.py @@ -3,8 +3,8 @@ Platform Serializers Serializers for platform-level operations (viewing tenants, users, metrics) """ from rest_framework import serializers -from core.models import Tenant, Domain -from smoothschedule.users.models import User +from smoothschedule.identity.core.models import Tenant, Domain +from smoothschedule.identity.users.models import User from .models import TenantInvitation, PlatformSettings, SubscriptionPlan, PlatformEmailAddress @@ -603,7 +603,7 @@ class TenantInvitationAcceptSerializer(serializers.Serializer): def validate_subdomain(self, value): """Validate subdomain is unique and valid""" import re - from core.models import Tenant, Domain + from smoothschedule.identity.core.models import Tenant, Domain # Check format (lowercase alphanumeric and hyphens, must start with letter) if not re.match(r'^[a-z][a-z0-9-]*$', value.lower()): @@ -722,7 +722,7 @@ class PlatformEmailAddressSerializer(serializers.ModelSerializer): """Validate and convert assigned_user_id to User instance.""" if value is None: return None - from smoothschedule.users.models import User + from smoothschedule.identity.users.models import User try: user = User.objects.get( pk=value, @@ -855,7 +855,7 @@ class PlatformEmailAddressUpdateSerializer(serializers.ModelSerializer): """Validate and convert assigned_user_id to User instance.""" if value is None: return None - from smoothschedule.users.models import User + from smoothschedule.identity.users.models import User try: user = User.objects.get( pk=value, diff --git a/smoothschedule/platform_admin/signals.py b/smoothschedule/smoothschedule/platform/admin/signals.py similarity index 100% rename from smoothschedule/platform_admin/signals.py rename to smoothschedule/smoothschedule/platform/admin/signals.py diff --git a/smoothschedule/platform_admin/tasks.py b/smoothschedule/smoothschedule/platform/admin/tasks.py similarity index 98% rename from smoothschedule/platform_admin/tasks.py rename to smoothschedule/smoothschedule/platform/admin/tasks.py index 3c7b378..4df64f9 100644 --- a/smoothschedule/platform_admin/tasks.py +++ b/smoothschedule/smoothschedule/platform/admin/tasks.py @@ -98,7 +98,7 @@ def send_appointment_reminder_email(self, event_id: int, customer_email: str, ho customer_email: Email address to send reminder to hours_before: Hours before the appointment (for context in email) """ - from schedule.models import Event + from smoothschedule.scheduling.schedule.models import Event try: event = Event.objects.select_related('created_by').prefetch_related( @@ -175,7 +175,7 @@ def send_bulk_appointment_reminders(hours_before: int = 24): Args: hours_before: How many hours before the appointment to send reminders """ - from schedule.models import Event + from smoothschedule.scheduling.schedule.models import Event from django.utils import timezone from datetime import timedelta @@ -221,7 +221,7 @@ def sync_subscription_plan_to_tenants(self, plan_id: int): plan_id: ID of the SubscriptionPlan that was updated """ from .models import SubscriptionPlan - from core.models import Tenant + from smoothschedule.identity.core.models import Tenant try: plan = SubscriptionPlan.objects.get(id=plan_id) diff --git a/smoothschedule/platform_admin/templates/platform_admin/emails/tenant_invitation.html b/smoothschedule/smoothschedule/platform/admin/templates/platform_admin/emails/tenant_invitation.html similarity index 100% rename from smoothschedule/platform_admin/templates/platform_admin/emails/tenant_invitation.html rename to smoothschedule/smoothschedule/platform/admin/templates/platform_admin/emails/tenant_invitation.html diff --git a/smoothschedule/platform_admin/urls.py b/smoothschedule/smoothschedule/platform/admin/urls.py similarity index 100% rename from smoothschedule/platform_admin/urls.py rename to smoothschedule/smoothschedule/platform/admin/urls.py diff --git a/smoothschedule/platform_admin/views.py b/smoothschedule/smoothschedule/platform/admin/views.py similarity index 99% rename from smoothschedule/platform_admin/views.py rename to smoothschedule/smoothschedule/platform/admin/views.py index 54a8de0..962aa9f 100644 --- a/smoothschedule/platform_admin/views.py +++ b/smoothschedule/smoothschedule/platform/admin/views.py @@ -15,8 +15,8 @@ from django.db import transaction, connection from django.utils import timezone from django_tenants.utils import schema_context -from core.models import Tenant, Domain -from smoothschedule.users.models import User +from smoothschedule.identity.core.models import Tenant, Domain +from smoothschedule.identity.users.models import User from .models import TenantInvitation, PlatformSettings, SubscriptionPlan, PlatformEmailAddress from .serializers import ( TenantSerializer, @@ -705,7 +705,7 @@ class SubscriptionPlanViewSet(viewsets.ModelViewSet): sync_subscription_plan_to_tenants.delay(plan.id) # Count tenants on this plan - from core.models import Tenant + from smoothschedule.identity.core.models import Tenant tenant_count = Tenant.objects.filter(subscription_plan=plan).count() return Response({ @@ -837,7 +837,7 @@ class TenantViewSet(viewsets.ModelViewSet): # First, unlink staff_resources from users WITHIN the tenant's schema # This prevents cross-schema SET_NULL cascade issues when users are deleted with schema_context(tenant.schema_name): - from schedule.models import Resource + from smoothschedule.scheduling.schedule.models import Resource # Unlink all resources from users (set user_id to NULL) Resource.objects.filter(user__isnull=False).update(user=None) @@ -851,7 +851,7 @@ class TenantViewSet(viewsets.ModelViewSet): Token.objects.filter(user_id__in=user_ids).delete() # Delete MFA-related objects - from smoothschedule.users.models import EmailVerificationToken, MFAVerificationCode, TrustedDevice + from smoothschedule.identity.users.models import EmailVerificationToken, MFAVerificationCode, TrustedDevice EmailVerificationToken.objects.filter(user_id__in=user_ids).delete() MFAVerificationCode.objects.filter(user_id__in=user_ids).delete() TrustedDevice.objects.filter(user_id__in=user_ids).delete() @@ -1321,7 +1321,7 @@ class PlatformEmailAddressViewSet(viewsets.ModelViewSet): @action(detail=False, methods=['get']) def assignable_users(self, request): """Get users that can be assigned to email addresses.""" - from smoothschedule.users.models import User + from smoothschedule.identity.users.models import User users = User.objects.filter( role__in=['superuser', 'platform_manager', 'platform_support'], diff --git a/smoothschedule/smoothschedule/platform/api/__init__.py b/smoothschedule/smoothschedule/platform/api/__init__.py new file mode 100644 index 0000000..274b5e3 --- /dev/null +++ b/smoothschedule/smoothschedule/platform/api/__init__.py @@ -0,0 +1 @@ +default_app_config = 'smoothschedule.platform.api.apps.PublicApiConfig' diff --git a/smoothschedule/smoothschedule/public_api/admin.py b/smoothschedule/smoothschedule/platform/api/admin.py similarity index 100% rename from smoothschedule/smoothschedule/public_api/admin.py rename to smoothschedule/smoothschedule/platform/api/admin.py diff --git a/smoothschedule/smoothschedule/public_api/apps.py b/smoothschedule/smoothschedule/platform/api/apps.py similarity index 63% rename from smoothschedule/smoothschedule/public_api/apps.py rename to smoothschedule/smoothschedule/platform/api/apps.py index 56ef9b5..3d29c0b 100644 --- a/smoothschedule/smoothschedule/public_api/apps.py +++ b/smoothschedule/smoothschedule/platform/api/apps.py @@ -3,12 +3,13 @@ from django.apps import AppConfig class PublicApiConfig(AppConfig): default_auto_field = 'django.db.models.BigAutoField' - name = 'smoothschedule.public_api' + name = 'smoothschedule.platform.api' + label = 'public_api' # Keep old label for migration compatibility verbose_name = 'Public API' def ready(self): # Import signals when app is ready try: - import smoothschedule.public_api.signals # noqa: F401 + from . import signals # noqa: F401 except ImportError: pass diff --git a/smoothschedule/smoothschedule/public_api/authentication.py b/smoothschedule/smoothschedule/platform/api/authentication.py similarity index 100% rename from smoothschedule/smoothschedule/public_api/authentication.py rename to smoothschedule/smoothschedule/platform/api/authentication.py diff --git a/smoothschedule/smoothschedule/public_api/migrations/0001_initial.py b/smoothschedule/smoothschedule/platform/api/migrations/0001_initial.py similarity index 100% rename from smoothschedule/smoothschedule/public_api/migrations/0001_initial.py rename to smoothschedule/smoothschedule/platform/api/migrations/0001_initial.py diff --git a/smoothschedule/smoothschedule/public_api/migrations/0002_add_sandbox_to_apitoken.py b/smoothschedule/smoothschedule/platform/api/migrations/0002_add_sandbox_to_apitoken.py similarity index 100% rename from smoothschedule/smoothschedule/public_api/migrations/0002_add_sandbox_to_apitoken.py rename to smoothschedule/smoothschedule/platform/api/migrations/0002_add_sandbox_to_apitoken.py diff --git a/smoothschedule/smoothschedule/public_api/migrations/0003_apitoken_plaintext_key.py b/smoothschedule/smoothschedule/platform/api/migrations/0003_apitoken_plaintext_key.py similarity index 100% rename from smoothschedule/smoothschedule/public_api/migrations/0003_apitoken_plaintext_key.py rename to smoothschedule/smoothschedule/platform/api/migrations/0003_apitoken_plaintext_key.py diff --git a/smoothschedule/smoothschedule/users/migrations/__init__.py b/smoothschedule/smoothschedule/platform/api/migrations/__init__.py similarity index 100% rename from smoothschedule/smoothschedule/users/migrations/__init__.py rename to smoothschedule/smoothschedule/platform/api/migrations/__init__.py diff --git a/smoothschedule/smoothschedule/public_api/models.py b/smoothschedule/smoothschedule/platform/api/models.py similarity index 99% rename from smoothschedule/smoothschedule/public_api/models.py rename to smoothschedule/smoothschedule/platform/api/models.py index 0e5c90e..40af3bd 100644 --- a/smoothschedule/smoothschedule/public_api/models.py +++ b/smoothschedule/smoothschedule/platform/api/models.py @@ -169,6 +169,7 @@ class APIToken(models.Model): ) class Meta: + app_label = 'public_api' verbose_name = 'API Token' verbose_name_plural = 'API Tokens' ordering = ['-created_at'] @@ -406,6 +407,7 @@ class WebhookSubscription(models.Model): MAX_CONSECUTIVE_FAILURES = 10 class Meta: + app_label = 'public_api' verbose_name = 'Webhook Subscription' verbose_name_plural = 'Webhook Subscriptions' ordering = ['-created_at'] @@ -525,6 +527,7 @@ class WebhookDelivery(models.Model): RETRY_DELAYS = [60, 300, 1800, 7200, 28800] class Meta: + app_label = 'public_api' verbose_name = 'Webhook Delivery' verbose_name_plural = 'Webhook Deliveries' ordering = ['-created_at'] diff --git a/smoothschedule/smoothschedule/public_api/permissions.py b/smoothschedule/smoothschedule/platform/api/permissions.py similarity index 100% rename from smoothschedule/smoothschedule/public_api/permissions.py rename to smoothschedule/smoothschedule/platform/api/permissions.py diff --git a/smoothschedule/smoothschedule/public_api/serializers.py b/smoothschedule/smoothschedule/platform/api/serializers.py similarity index 100% rename from smoothschedule/smoothschedule/public_api/serializers.py rename to smoothschedule/smoothschedule/platform/api/serializers.py diff --git a/smoothschedule/smoothschedule/public_api/signals.py b/smoothschedule/smoothschedule/platform/api/signals.py similarity index 97% rename from smoothschedule/smoothschedule/public_api/signals.py rename to smoothschedule/smoothschedule/platform/api/signals.py index 30d892c..59a3701 100644 --- a/smoothschedule/smoothschedule/public_api/signals.py +++ b/smoothschedule/smoothschedule/platform/api/signals.py @@ -171,14 +171,14 @@ def register_webhook_signals(): Call this from the app's ready() method to set up the signals. """ try: - from smoothschedule.schedule.models import Event + from smoothschedule.scheduling.schedule.models import Event post_save.connect(handle_appointment_created, sender=Event, dispatch_uid='webhook_appointment_created') post_save.connect(handle_appointment_updated, sender=Event, dispatch_uid='webhook_appointment_updated') except ImportError: pass try: - from smoothschedule.users.models import User + from smoothschedule.identity.users.models import User post_save.connect(handle_customer_created, sender=User, dispatch_uid='webhook_customer_created') post_save.connect(handle_customer_updated, sender=User, dispatch_uid='webhook_customer_updated') except ImportError: diff --git a/smoothschedule/smoothschedule/public_api/tests_token_security.py b/smoothschedule/smoothschedule/platform/api/tests_token_security.py similarity index 97% rename from smoothschedule/smoothschedule/public_api/tests_token_security.py rename to smoothschedule/smoothschedule/platform/api/tests_token_security.py index 80f102d..65bdb3c 100644 --- a/smoothschedule/smoothschedule/public_api/tests_token_security.py +++ b/smoothschedule/smoothschedule/platform/api/tests_token_security.py @@ -6,9 +6,9 @@ plaintext keys stored in the database, only sandbox/test tokens. """ from django.test import TestCase from django.core.exceptions import ValidationError -from core.models import Tenant -from smoothschedule.users.models import User -from smoothschedule.public_api.models import APIToken +from smoothschedule.identity.core.models import Tenant +from smoothschedule.identity.users.models import User +from smoothschedule.platform.api.models import APIToken class APITokenPlaintextSecurityTests(TestCase): @@ -28,7 +28,7 @@ class APITokenPlaintextSecurityTests(TestCase): ) # Create domain for the tenant - from core.models import Domain + from smoothschedule.identity.core.models import Domain self.domain = Domain.objects.create( domain='test-security.localhost', tenant=self.tenant, diff --git a/smoothschedule/smoothschedule/public_api/throttling.py b/smoothschedule/smoothschedule/platform/api/throttling.py similarity index 100% rename from smoothschedule/smoothschedule/public_api/throttling.py rename to smoothschedule/smoothschedule/platform/api/throttling.py diff --git a/smoothschedule/smoothschedule/public_api/urls.py b/smoothschedule/smoothschedule/platform/api/urls.py similarity index 98% rename from smoothschedule/smoothschedule/public_api/urls.py rename to smoothschedule/smoothschedule/platform/api/urls.py index 073b71d..903dbed 100644 --- a/smoothschedule/smoothschedule/public_api/urls.py +++ b/smoothschedule/smoothschedule/platform/api/urls.py @@ -60,7 +60,7 @@ class PublicRedocView(SpectacularRedocView): urlpatterns = [ # OpenAPI Schema & Documentation (public, no auth required) path('schema/', PublicSchemaView.as_view( - urlconf='smoothschedule.public_api.urls', + urlconf='smoothschedule.platform.api.urls', custom_settings={ 'TITLE': 'SmoothSchedule Public API', 'DESCRIPTION': ''' diff --git a/smoothschedule/smoothschedule/public_api/views.py b/smoothschedule/smoothschedule/platform/api/views.py similarity index 98% rename from smoothschedule/smoothschedule/public_api/views.py rename to smoothschedule/smoothschedule/platform/api/views.py index 924102c..03e3064 100644 --- a/smoothschedule/smoothschedule/public_api/views.py +++ b/smoothschedule/smoothschedule/platform/api/views.py @@ -433,7 +433,7 @@ class PublicServiceViewSet(PublicAPIViewMixin, viewsets.ViewSet): def list(self, request): """List all active services.""" - from smoothschedule.schedule.models import Service + from smoothschedule.scheduling.schedule.models import Service services = Service.objects.filter(is_active=True).order_by('display_order', 'name') @@ -457,7 +457,7 @@ class PublicServiceViewSet(PublicAPIViewMixin, viewsets.ViewSet): def retrieve(self, request, pk=None): """Get a specific service.""" - from smoothschedule.schedule.models import Service + from smoothschedule.scheduling.schedule.models import Service try: service = Service.objects.get(pk=pk, is_active=True) @@ -520,7 +520,7 @@ class PublicResourceViewSet(PublicAPIViewMixin, viewsets.ViewSet): def list(self, request): """List all active resources.""" - from smoothschedule.schedule.models import Resource + from smoothschedule.scheduling.schedule.models import Resource queryset = Resource.objects.filter(is_active=True).select_related('resource_type') @@ -548,7 +548,7 @@ class PublicResourceViewSet(PublicAPIViewMixin, viewsets.ViewSet): def retrieve(self, request, pk=None): """Get a specific resource.""" - from smoothschedule.schedule.models import Resource + from smoothschedule.scheduling.schedule.models import Resource try: resource = Resource.objects.select_related('resource_type').get(pk=pk, is_active=True) @@ -636,7 +636,7 @@ class AvailabilityView(PublicAPIViewMixin, APIView): status=status.HTTP_400_BAD_REQUEST ) - from smoothschedule.schedule.models import Service, Resource, Event + from smoothschedule.scheduling.schedule.models import Service, Resource, Event # Get the service service_id = serializer.validated_data['service_id'] @@ -790,7 +790,7 @@ class PublicAppointmentViewSet(PublicAPIViewMixin, viewsets.ViewSet): def list(self, request): """List appointments with optional filters.""" - from smoothschedule.schedule.models import Event + from smoothschedule.scheduling.schedule.models import Event queryset = Event.objects.all() @@ -853,7 +853,7 @@ class PublicAppointmentViewSet(PublicAPIViewMixin, viewsets.ViewSet): def retrieve(self, request, pk=None): """Get appointment details.""" - from smoothschedule.schedule.models import Event + from smoothschedule.scheduling.schedule.models import Event try: event = Event.objects.get(pk=pk) @@ -895,7 +895,7 @@ class PublicAppointmentViewSet(PublicAPIViewMixin, viewsets.ViewSet): def destroy(self, request, pk=None): """Cancel an appointment.""" - from smoothschedule.schedule.models import Event + from smoothschedule.scheduling.schedule.models import Event try: event = Event.objects.get(pk=pk) @@ -982,7 +982,7 @@ class PublicCustomerViewSet(PublicAPIViewMixin, viewsets.ViewSet): def list(self, request): """List customers with optional filters.""" - from smoothschedule.users.models import User + from smoothschedule.identity.users.models import User queryset = User.objects.filter(role='CUSTOMER') @@ -1037,7 +1037,7 @@ class PublicCustomerViewSet(PublicAPIViewMixin, viewsets.ViewSet): def retrieve(self, request, pk=None): """Get customer details.""" - from smoothschedule.users.models import User + from smoothschedule.identity.users.models import User # Filter by sandbox mode is_sandbox = getattr(request, 'sandbox_mode', False) diff --git a/smoothschedule/smoothschedule/public_api/webhooks.py b/smoothschedule/smoothschedule/platform/api/webhooks.py similarity index 100% rename from smoothschedule/smoothschedule/public_api/webhooks.py rename to smoothschedule/smoothschedule/platform/api/webhooks.py diff --git a/smoothschedule/smoothschedule/public_api/__init__.py b/smoothschedule/smoothschedule/public_api/__init__.py deleted file mode 100644 index b9966ed..0000000 --- a/smoothschedule/smoothschedule/public_api/__init__.py +++ /dev/null @@ -1 +0,0 @@ -default_app_config = 'smoothschedule.public_api.apps.PublicApiConfig' diff --git a/smoothschedule/smoothschedule/users/tests/__init__.py b/smoothschedule/smoothschedule/scheduling/__init__.py similarity index 100% rename from smoothschedule/smoothschedule/users/tests/__init__.py rename to smoothschedule/smoothschedule/scheduling/__init__.py diff --git a/smoothschedule/analytics/IMPLEMENTATION_GUIDE.md b/smoothschedule/smoothschedule/scheduling/analytics/IMPLEMENTATION_GUIDE.md similarity index 100% rename from smoothschedule/analytics/IMPLEMENTATION_GUIDE.md rename to smoothschedule/smoothschedule/scheduling/analytics/IMPLEMENTATION_GUIDE.md diff --git a/smoothschedule/analytics/README.md b/smoothschedule/smoothschedule/scheduling/analytics/README.md similarity index 100% rename from smoothschedule/analytics/README.md rename to smoothschedule/smoothschedule/scheduling/analytics/README.md diff --git a/smoothschedule/smoothschedule/users/tests/api/__init__.py b/smoothschedule/smoothschedule/scheduling/analytics/__init__.py similarity index 100% rename from smoothschedule/smoothschedule/users/tests/api/__init__.py rename to smoothschedule/smoothschedule/scheduling/analytics/__init__.py diff --git a/smoothschedule/analytics/admin.py b/smoothschedule/smoothschedule/scheduling/analytics/admin.py similarity index 100% rename from smoothschedule/analytics/admin.py rename to smoothschedule/smoothschedule/scheduling/analytics/admin.py diff --git a/smoothschedule/analytics/apps.py b/smoothschedule/smoothschedule/scheduling/analytics/apps.py similarity index 72% rename from smoothschedule/analytics/apps.py rename to smoothschedule/smoothschedule/scheduling/analytics/apps.py index a11242e..d3b5c02 100644 --- a/smoothschedule/analytics/apps.py +++ b/smoothschedule/smoothschedule/scheduling/analytics/apps.py @@ -6,5 +6,6 @@ from django.apps import AppConfig class AnalyticsConfig(AppConfig): default_auto_field = 'django.db.models.BigAutoField' - name = 'analytics' + name = 'smoothschedule.scheduling.analytics' + label = 'analytics' verbose_name = 'Analytics' diff --git a/smoothschedule/tickets/__init__.py b/smoothschedule/smoothschedule/scheduling/analytics/migrations/__init__.py similarity index 100% rename from smoothschedule/tickets/__init__.py rename to smoothschedule/smoothschedule/scheduling/analytics/migrations/__init__.py diff --git a/smoothschedule/analytics/serializers.py b/smoothschedule/smoothschedule/scheduling/analytics/serializers.py similarity index 100% rename from smoothschedule/analytics/serializers.py rename to smoothschedule/smoothschedule/scheduling/analytics/serializers.py diff --git a/smoothschedule/analytics/tests.py b/smoothschedule/smoothschedule/scheduling/analytics/tests.py similarity index 98% rename from smoothschedule/analytics/tests.py rename to smoothschedule/smoothschedule/scheduling/analytics/tests.py index 1a8f5c1..759cbc8 100644 --- a/smoothschedule/analytics/tests.py +++ b/smoothschedule/smoothschedule/scheduling/analytics/tests.py @@ -10,9 +10,9 @@ from rest_framework.test import APIClient from rest_framework.authtoken.models import Token from datetime import timedelta -from core.models import Tenant -from schedule.models import Event, Resource, Service -from platform_admin.models import SubscriptionPlan +from smoothschedule.identity.core.models import Tenant +from smoothschedule.scheduling.schedule.models import Event, Resource, Service +from smoothschedule.platform.admin.models import SubscriptionPlan User = get_user_model() diff --git a/smoothschedule/analytics/urls.py b/smoothschedule/smoothschedule/scheduling/analytics/urls.py similarity index 100% rename from smoothschedule/analytics/urls.py rename to smoothschedule/smoothschedule/scheduling/analytics/urls.py diff --git a/smoothschedule/analytics/views.py b/smoothschedule/smoothschedule/scheduling/analytics/views.py similarity index 98% rename from smoothschedule/analytics/views.py rename to smoothschedule/smoothschedule/scheduling/analytics/views.py index 471ad66..f1394b9 100644 --- a/smoothschedule/analytics/views.py +++ b/smoothschedule/smoothschedule/scheduling/analytics/views.py @@ -12,9 +12,9 @@ from rest_framework.permissions import IsAuthenticated from rest_framework.response import Response from datetime import timedelta, datetime -from core.permissions import HasFeaturePermission -from schedule.models import Event, Service, Participant -from smoothschedule.users.models import User +from smoothschedule.identity.core.permissions import HasFeaturePermission +from smoothschedule.scheduling.schedule.models import Event, Service, Participant +from smoothschedule.identity.users.models import User class AnalyticsViewSet(viewsets.ViewSet): @@ -322,7 +322,7 @@ class AnalyticsViewSet(viewsets.ViewSet): "period_days": int } """ - from payments.models import Payment + from smoothschedule.commerce.payments.models import Payment # Check if tenant has payment permissions tenant = getattr(request, 'tenant', None) diff --git a/smoothschedule/contracts/README_PDF.md b/smoothschedule/smoothschedule/scheduling/contracts/README_PDF.md similarity index 100% rename from smoothschedule/contracts/README_PDF.md rename to smoothschedule/smoothschedule/scheduling/contracts/README_PDF.md diff --git a/smoothschedule/tickets/management/__init__.py b/smoothschedule/smoothschedule/scheduling/contracts/__init__.py similarity index 100% rename from smoothschedule/tickets/management/__init__.py rename to smoothschedule/smoothschedule/scheduling/contracts/__init__.py diff --git a/smoothschedule/payments/admin.py b/smoothschedule/smoothschedule/scheduling/contracts/admin.py similarity index 100% rename from smoothschedule/payments/admin.py rename to smoothschedule/smoothschedule/scheduling/contracts/admin.py diff --git a/smoothschedule/contracts/apps.py b/smoothschedule/smoothschedule/scheduling/contracts/apps.py similarity index 63% rename from smoothschedule/contracts/apps.py rename to smoothschedule/smoothschedule/scheduling/contracts/apps.py index 82de8d1..49e531d 100644 --- a/smoothschedule/contracts/apps.py +++ b/smoothschedule/smoothschedule/scheduling/contracts/apps.py @@ -3,4 +3,5 @@ from django.apps import AppConfig class ContractsConfig(AppConfig): default_auto_field = 'django.db.models.BigAutoField' - name = 'contracts' + name = 'smoothschedule.scheduling.contracts' + label = 'contracts' diff --git a/smoothschedule/contracts/migrations/0001_initial.py b/smoothschedule/smoothschedule/scheduling/contracts/migrations/0001_initial.py similarity index 100% rename from smoothschedule/contracts/migrations/0001_initial.py rename to smoothschedule/smoothschedule/scheduling/contracts/migrations/0001_initial.py diff --git a/smoothschedule/tickets/management/commands/__init__.py b/smoothschedule/smoothschedule/scheduling/contracts/migrations/__init__.py similarity index 100% rename from smoothschedule/tickets/management/commands/__init__.py rename to smoothschedule/smoothschedule/scheduling/contracts/migrations/__init__.py diff --git a/smoothschedule/contracts/models.py b/smoothschedule/smoothschedule/scheduling/contracts/models.py similarity index 98% rename from smoothschedule/contracts/models.py rename to smoothschedule/smoothschedule/scheduling/contracts/models.py index f74f7cf..4b53265 100644 --- a/smoothschedule/contracts/models.py +++ b/smoothschedule/smoothschedule/scheduling/contracts/models.py @@ -63,6 +63,7 @@ class ContractTemplate(models.Model): updated_at = models.DateTimeField(auto_now=True) class Meta: + app_label = 'contracts' ordering = ["name"] def __str__(self): @@ -94,6 +95,7 @@ class ServiceContractRequirement(models.Model): created_at = models.DateTimeField(auto_now_add=True) class Meta: + app_label = 'contracts' ordering = ["display_order"] unique_together = ["service", "template"] @@ -177,6 +179,7 @@ class Contract(models.Model): pdf_path = models.CharField(max_length=500, blank=True) class Meta: + app_label = 'contracts' ordering = ["-created_at"] indexes = [ models.Index(fields=["signing_token"]), @@ -257,6 +260,7 @@ class ContractSignature(models.Model): ) class Meta: + app_label = 'contracts' indexes = [ models.Index(fields=["signed_at"]), ] diff --git a/smoothschedule/contracts/pdf_service.py b/smoothschedule/smoothschedule/scheduling/contracts/pdf_service.py similarity index 98% rename from smoothschedule/contracts/pdf_service.py rename to smoothschedule/smoothschedule/scheduling/contracts/pdf_service.py index 67acd1a..e5ac939 100644 --- a/smoothschedule/contracts/pdf_service.py +++ b/smoothschedule/smoothschedule/scheduling/contracts/pdf_service.py @@ -63,7 +63,7 @@ class ContractPDFService: # Get tenant/business info from django.db import connection - from core.models import Tenant + from smoothschedule.identity.core.models import Tenant tenant = None if hasattr(connection, 'tenant'): @@ -209,7 +209,7 @@ class ContractPDFService: from django.db import connection from django.utils import timezone - from core.models import Tenant + from smoothschedule.identity.core.models import Tenant # Get tenant info tenant = None @@ -327,7 +327,7 @@ class ContractPDFService: import hashlib from django.db import connection from django.utils import timezone - from core.models import Tenant + from smoothschedule.identity.core.models import Tenant signature = contract.signature @@ -406,7 +406,7 @@ class ContractPDFService: import hashlib from django.utils import timezone from django.db import connection - from core.models import Tenant + from smoothschedule.identity.core.models import Tenant if contract.status != 'SIGNED': raise ValueError("Contract must be signed for legal export") diff --git a/smoothschedule/contracts/serializers.py b/smoothschedule/smoothschedule/scheduling/contracts/serializers.py similarity index 97% rename from smoothschedule/contracts/serializers.py rename to smoothschedule/smoothschedule/scheduling/contracts/serializers.py index fced290..4aa82b1 100644 --- a/smoothschedule/contracts/serializers.py +++ b/smoothschedule/smoothschedule/scheduling/contracts/serializers.py @@ -130,7 +130,7 @@ class PublicContractSerializer(serializers.Serializer): def to_representation(self, instance): from django.db import connection from django.utils import timezone - from core.models import Tenant + from smoothschedule.identity.core.models import Tenant # Get business info try: @@ -210,7 +210,7 @@ class CreateContractSerializer(serializers.Serializer): send_email = serializers.BooleanField(default=True) def validate_customer_id(self, value): - from smoothschedule.users.models import User + from smoothschedule.identity.users.models import User try: customer = User.objects.get(id=value, role=User.Role.CUSTOMER) return customer @@ -220,7 +220,7 @@ class CreateContractSerializer(serializers.Serializer): def validate_event_id(self, value): if value is None: return None - from schedule.models import Event + from smoothschedule.scheduling.schedule.models import Event try: return Event.objects.get(id=value) except Event.DoesNotExist: diff --git a/smoothschedule/contracts/tasks.py b/smoothschedule/smoothschedule/scheduling/contracts/tasks.py similarity index 98% rename from smoothschedule/contracts/tasks.py rename to smoothschedule/smoothschedule/scheduling/contracts/tasks.py index 9a2dfec..097184f 100644 --- a/smoothschedule/contracts/tasks.py +++ b/smoothschedule/smoothschedule/scheduling/contracts/tasks.py @@ -26,7 +26,7 @@ def send_contract_email(self, contract_id): """ from .models import Contract from django.db import connection - from core.models import Tenant + from smoothschedule.identity.core.models import Tenant try: contract = Contract.objects.select_related('customer', 'template').get(id=contract_id) @@ -104,7 +104,7 @@ def send_contract_reminder(self, contract_id): """ from .models import Contract from django.db import connection - from core.models import Tenant + from smoothschedule.identity.core.models import Tenant try: contract = Contract.objects.select_related('customer').get(id=contract_id) @@ -181,8 +181,8 @@ def send_contract_signed_emails(self, contract_id): """ from .models import Contract from django.db import connection - from core.models import Tenant - from smoothschedule.users.models import User + from smoothschedule.identity.core.models import Tenant + from smoothschedule.identity.users.models import User try: contract = Contract.objects.select_related('customer', 'signature').get(id=contract_id) diff --git a/smoothschedule/contracts/templates/contracts/pdf_preview_template.html b/smoothschedule/smoothschedule/scheduling/contracts/templates/contracts/pdf_preview_template.html similarity index 100% rename from smoothschedule/contracts/templates/contracts/pdf_preview_template.html rename to smoothschedule/smoothschedule/scheduling/contracts/templates/contracts/pdf_preview_template.html diff --git a/smoothschedule/contracts/templates/contracts/pdf_template.html b/smoothschedule/smoothschedule/scheduling/contracts/templates/contracts/pdf_template.html similarity index 100% rename from smoothschedule/contracts/templates/contracts/pdf_template.html rename to smoothschedule/smoothschedule/scheduling/contracts/templates/contracts/pdf_template.html diff --git a/smoothschedule/schedule/tests.py b/smoothschedule/smoothschedule/scheduling/contracts/tests.py similarity index 100% rename from smoothschedule/schedule/tests.py rename to smoothschedule/smoothschedule/scheduling/contracts/tests.py diff --git a/smoothschedule/contracts/urls.py b/smoothschedule/smoothschedule/scheduling/contracts/urls.py similarity index 100% rename from smoothschedule/contracts/urls.py rename to smoothschedule/smoothschedule/scheduling/contracts/urls.py diff --git a/smoothschedule/contracts/views.py b/smoothschedule/smoothschedule/scheduling/contracts/views.py similarity index 99% rename from smoothschedule/contracts/views.py rename to smoothschedule/smoothschedule/scheduling/contracts/views.py index 4c52554..26a595d 100644 --- a/smoothschedule/contracts/views.py +++ b/smoothschedule/smoothschedule/scheduling/contracts/views.py @@ -251,7 +251,7 @@ class ContractViewSet(viewsets.ModelViewSet): def _render_template(self, template, customer, event=None): """Render template with variable substitution""" - from core.models import Tenant + from smoothschedule.identity.core.models import Tenant tenant = Tenant.objects.get(schema_name=connection.schema_name) diff --git a/smoothschedule/tickets/migrations/__init__.py b/smoothschedule/smoothschedule/scheduling/schedule/__init__.py similarity index 100% rename from smoothschedule/tickets/migrations/__init__.py rename to smoothschedule/smoothschedule/scheduling/schedule/__init__.py diff --git a/smoothschedule/schedule/admin.py b/smoothschedule/smoothschedule/scheduling/schedule/admin.py similarity index 100% rename from smoothschedule/schedule/admin.py rename to smoothschedule/smoothschedule/scheduling/schedule/admin.py diff --git a/smoothschedule/schedule/api_views.py b/smoothschedule/smoothschedule/scheduling/schedule/api_views.py similarity index 99% rename from smoothschedule/schedule/api_views.py rename to smoothschedule/smoothschedule/scheduling/schedule/api_views.py index e5f8332..3694306 100644 --- a/smoothschedule/schedule/api_views.py +++ b/smoothschedule/smoothschedule/scheduling/schedule/api_views.py @@ -450,7 +450,7 @@ def custom_domains_view(request): if user.role.lower() != 'tenant_owner': return Response({'error': 'Only business owners can manage domains'}, status=status.HTTP_403_FORBIDDEN) - from core.models import Domain + from smoothschedule.identity.core.models import Domain if request.method == 'GET': # List all domains for this tenant @@ -526,7 +526,7 @@ def custom_domain_detail_view(request, domain_id): if user.role.lower() != 'tenant_owner': return Response({'error': 'Only business owners can manage domains'}, status=status.HTTP_403_FORBIDDEN) - from core.models import Domain + from smoothschedule.identity.core.models import Domain try: domain = Domain.objects.get(id=domain_id, tenant=tenant) @@ -571,7 +571,7 @@ def custom_domain_verify_view(request, domain_id): if user.role.lower() != 'tenant_owner': return Response({'error': 'Only business owners can manage domains'}, status=status.HTTP_403_FORBIDDEN) - from core.models import Domain + from smoothschedule.identity.core.models import Domain from django.utils import timezone import socket @@ -614,7 +614,7 @@ def custom_domain_set_primary_view(request, domain_id): if user.role.lower() != 'tenant_owner': return Response({'error': 'Only business owners can manage domains'}, status=status.HTTP_403_FORBIDDEN) - from core.models import Domain + from smoothschedule.identity.core.models import Domain try: domain = Domain.objects.get(id=domain_id, tenant=tenant) diff --git a/smoothschedule/schedule/apps.py b/smoothschedule/smoothschedule/scheduling/schedule/apps.py similarity index 92% rename from smoothschedule/schedule/apps.py rename to smoothschedule/smoothschedule/scheduling/schedule/apps.py index 6701dce..61cd143 100644 --- a/smoothschedule/schedule/apps.py +++ b/smoothschedule/smoothschedule/scheduling/schedule/apps.py @@ -3,7 +3,8 @@ from django.apps import AppConfig class ScheduleConfig(AppConfig): default_auto_field = 'django.db.models.BigAutoField' - name = 'schedule' + name = 'smoothschedule.scheduling.schedule' + label = 'schedule' verbose_name = 'Schedule Management' def ready(self): diff --git a/smoothschedule/schedule/builtin_plugins.py b/smoothschedule/smoothschedule/scheduling/schedule/builtin_plugins.py similarity index 99% rename from smoothschedule/schedule/builtin_plugins.py rename to smoothschedule/smoothschedule/scheduling/schedule/builtin_plugins.py index ef8a572..a5c6311 100644 --- a/smoothschedule/schedule/builtin_plugins.py +++ b/smoothschedule/smoothschedule/scheduling/schedule/builtin_plugins.py @@ -273,7 +273,7 @@ class AppointmentReminderPlugin(BasePlugin): def execute(self, context: Dict[str, Any]) -> Dict[str, Any]: from .models import Event - from platform_admin.tasks import send_appointment_reminder_email + from smoothschedule.platform.admin.tasks import send_appointment_reminder_email hours_before = self.config.get('hours_before', 24) method = self.config.get('method', 'email') diff --git a/smoothschedule/schedule/calendar_sync_urls.py b/smoothschedule/smoothschedule/scheduling/schedule/calendar_sync_urls.py similarity index 100% rename from smoothschedule/schedule/calendar_sync_urls.py rename to smoothschedule/smoothschedule/scheduling/schedule/calendar_sync_urls.py diff --git a/smoothschedule/schedule/calendar_sync_views.py b/smoothschedule/smoothschedule/scheduling/schedule/calendar_sync_views.py similarity index 98% rename from smoothschedule/schedule/calendar_sync_views.py rename to smoothschedule/smoothschedule/scheduling/schedule/calendar_sync_views.py index 601bdbd..61a3e9e 100644 --- a/smoothschedule/schedule/calendar_sync_views.py +++ b/smoothschedule/smoothschedule/scheduling/schedule/calendar_sync_views.py @@ -18,8 +18,8 @@ from rest_framework.response import Response from rest_framework.permissions import IsAuthenticated from rest_framework.decorators import action -from core.models import OAuthCredential, Tenant -from core.permissions import HasFeaturePermission +from smoothschedule.identity.core.models import OAuthCredential, Tenant +from smoothschedule.identity.core.permissions import HasFeaturePermission logger = logging.getLogger(__name__) diff --git a/smoothschedule/schedule/consumers.py b/smoothschedule/smoothschedule/scheduling/schedule/consumers.py similarity index 99% rename from smoothschedule/schedule/consumers.py rename to smoothschedule/smoothschedule/scheduling/schedule/consumers.py index 1def075..8586485 100644 --- a/smoothschedule/schedule/consumers.py +++ b/smoothschedule/smoothschedule/scheduling/schedule/consumers.py @@ -231,7 +231,7 @@ def get_event_staff_user_ids(event): Returns list of user IDs for broadcasting. """ from schedule.models import Participant, Resource - from smoothschedule.users.models import User + from smoothschedule.identity.users.models import User user_ids = set() diff --git a/smoothschedule/schedule/custom_script_plugin.py b/smoothschedule/smoothschedule/scheduling/schedule/custom_script_plugin.py similarity index 100% rename from smoothschedule/schedule/custom_script_plugin.py rename to smoothschedule/smoothschedule/scheduling/schedule/custom_script_plugin.py diff --git a/smoothschedule/schedule/email_template_presets.py b/smoothschedule/smoothschedule/scheduling/schedule/email_template_presets.py similarity index 100% rename from smoothschedule/schedule/email_template_presets.py rename to smoothschedule/smoothschedule/scheduling/schedule/email_template_presets.py diff --git a/smoothschedule/schedule/example_automation.py b/smoothschedule/smoothschedule/scheduling/schedule/example_automation.py similarity index 99% rename from smoothschedule/schedule/example_automation.py rename to smoothschedule/smoothschedule/scheduling/schedule/example_automation.py index 2732265..323c570 100644 --- a/smoothschedule/schedule/example_automation.py +++ b/smoothschedule/smoothschedule/scheduling/schedule/example_automation.py @@ -99,7 +99,7 @@ Looking forward to seeing you soon! """Execute the re-engagement campaign""" from .models import Event - from smoothschedule.users.models import User + from smoothschedule.identity.users.models import User business = context.get('business') if not business: @@ -169,7 +169,7 @@ Looking forward to seeing you soon! def _find_inactive_customers(self, cutoff_date, min_visits, max_count): """Find customers who haven't booked recently""" from .models import Event, Participant - from smoothschedule.users.models import User + from smoothschedule.identity.users.models import User from django.contrib.contenttypes.models import ContentType # Get customer content type diff --git a/smoothschedule/schedule/export_views.py b/smoothschedule/smoothschedule/scheduling/schedule/export_views.py similarity index 99% rename from smoothschedule/schedule/export_views.py rename to smoothschedule/smoothschedule/scheduling/schedule/export_views.py index 227ec31..0eaab2f 100644 --- a/smoothschedule/schedule/export_views.py +++ b/smoothschedule/smoothschedule/scheduling/schedule/export_views.py @@ -17,8 +17,8 @@ from rest_framework.response import Response from rest_framework.exceptions import PermissionDenied from .models import Event, Resource, Service -from smoothschedule.users.models import User -from core.models import Tenant +from smoothschedule.identity.users.models import User +from smoothschedule.identity.core.models import Tenant class HasExportDataPermission: diff --git a/smoothschedule/smoothschedule/scheduling/schedule/management/__init__.py b/smoothschedule/smoothschedule/scheduling/schedule/management/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/smoothschedule/smoothschedule/scheduling/schedule/management/commands/__init__.py b/smoothschedule/smoothschedule/scheduling/schedule/management/commands/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/smoothschedule/schedule/management/commands/create_demo_appointments.py b/smoothschedule/smoothschedule/scheduling/schedule/management/commands/create_demo_appointments.py similarity index 97% rename from smoothschedule/schedule/management/commands/create_demo_appointments.py rename to smoothschedule/smoothschedule/scheduling/schedule/management/commands/create_demo_appointments.py index 5381979..9f2721d 100644 --- a/smoothschedule/schedule/management/commands/create_demo_appointments.py +++ b/smoothschedule/smoothschedule/scheduling/schedule/management/commands/create_demo_appointments.py @@ -9,8 +9,8 @@ from django.contrib.contenttypes.models import ContentType from django.core.management.base import BaseCommand from django.utils import timezone -from schedule.models import Event, Resource, Service, Participant -from smoothschedule.users.models import User +from smoothschedule.scheduling.schedule.models import Event, Resource, Service, Participant +from smoothschedule.identity.users.models import User class Command(BaseCommand): diff --git a/smoothschedule/schedule/management/commands/seed_email_templates.py b/smoothschedule/smoothschedule/scheduling/schedule/management/commands/seed_email_templates.py similarity index 100% rename from smoothschedule/schedule/management/commands/seed_email_templates.py rename to smoothschedule/smoothschedule/scheduling/schedule/management/commands/seed_email_templates.py diff --git a/smoothschedule/schedule/management/commands/seed_holidays.py b/smoothschedule/smoothschedule/scheduling/schedule/management/commands/seed_holidays.py similarity index 98% rename from smoothschedule/schedule/management/commands/seed_holidays.py rename to smoothschedule/smoothschedule/scheduling/schedule/management/commands/seed_holidays.py index cb23ecd..f4267ff 100644 --- a/smoothschedule/schedule/management/commands/seed_holidays.py +++ b/smoothschedule/smoothschedule/scheduling/schedule/management/commands/seed_holidays.py @@ -1,7 +1,7 @@ """Management command to seed US holidays.""" from django.core.management.base import BaseCommand -from schedule.models import Holiday +from smoothschedule.scheduling.schedule.models import Holiday US_HOLIDAYS = [ diff --git a/smoothschedule/schedule/management/commands/seed_platform_plugins.py b/smoothschedule/smoothschedule/scheduling/schedule/management/commands/seed_platform_plugins.py similarity index 99% rename from smoothschedule/schedule/management/commands/seed_platform_plugins.py rename to smoothschedule/smoothschedule/scheduling/schedule/management/commands/seed_platform_plugins.py index bb92fb4..681af86 100644 --- a/smoothschedule/schedule/management/commands/seed_platform_plugins.py +++ b/smoothschedule/smoothschedule/scheduling/schedule/management/commands/seed_platform_plugins.py @@ -1,6 +1,6 @@ from django.core.management.base import BaseCommand from django.utils import timezone -from schedule.models import PluginTemplate +from smoothschedule.scheduling.schedule.models import PluginTemplate def get_platform_plugins(): diff --git a/smoothschedule/schedule/migrations/0001_initial.py b/smoothschedule/smoothschedule/scheduling/schedule/migrations/0001_initial.py similarity index 100% rename from smoothschedule/schedule/migrations/0001_initial.py rename to smoothschedule/smoothschedule/scheduling/schedule/migrations/0001_initial.py diff --git a/smoothschedule/schedule/migrations/0002_add_service_model.py b/smoothschedule/smoothschedule/scheduling/schedule/migrations/0002_add_service_model.py similarity index 100% rename from smoothschedule/schedule/migrations/0002_add_service_model.py rename to smoothschedule/smoothschedule/scheduling/schedule/migrations/0002_add_service_model.py diff --git a/smoothschedule/schedule/migrations/0003_add_resource_type.py b/smoothschedule/smoothschedule/scheduling/schedule/migrations/0003_add_resource_type.py similarity index 100% rename from smoothschedule/schedule/migrations/0003_add_resource_type.py rename to smoothschedule/smoothschedule/scheduling/schedule/migrations/0003_add_resource_type.py diff --git a/smoothschedule/schedule/migrations/0004_rename_schedule_se_is_acti_idx_schedule_se_is_acti_8c055e_idx.py b/smoothschedule/smoothschedule/scheduling/schedule/migrations/0004_rename_schedule_se_is_acti_idx_schedule_se_is_acti_8c055e_idx.py similarity index 100% rename from smoothschedule/schedule/migrations/0004_rename_schedule_se_is_acti_idx_schedule_se_is_acti_8c055e_idx.py rename to smoothschedule/smoothschedule/scheduling/schedule/migrations/0004_rename_schedule_se_is_acti_idx_schedule_se_is_acti_8c055e_idx.py diff --git a/smoothschedule/schedule/migrations/0005_resource_saved_lane_count.py b/smoothschedule/smoothschedule/scheduling/schedule/migrations/0005_resource_saved_lane_count.py similarity index 100% rename from smoothschedule/schedule/migrations/0005_resource_saved_lane_count.py rename to smoothschedule/smoothschedule/scheduling/schedule/migrations/0005_resource_saved_lane_count.py diff --git a/smoothschedule/schedule/migrations/0006_add_user_to_resource.py b/smoothschedule/smoothschedule/scheduling/schedule/migrations/0006_add_user_to_resource.py similarity index 100% rename from smoothschedule/schedule/migrations/0006_add_user_to_resource.py rename to smoothschedule/smoothschedule/scheduling/schedule/migrations/0006_add_user_to_resource.py diff --git a/smoothschedule/schedule/migrations/0007_alter_resource_type_resourcetype_and_more.py b/smoothschedule/smoothschedule/scheduling/schedule/migrations/0007_alter_resource_type_resourcetype_and_more.py similarity index 100% rename from smoothschedule/schedule/migrations/0007_alter_resource_type_resourcetype_and_more.py rename to smoothschedule/smoothschedule/scheduling/schedule/migrations/0007_alter_resource_type_resourcetype_and_more.py diff --git a/smoothschedule/schedule/migrations/0008_create_default_resource_types.py b/smoothschedule/smoothschedule/scheduling/schedule/migrations/0008_create_default_resource_types.py similarity index 100% rename from smoothschedule/schedule/migrations/0008_create_default_resource_types.py rename to smoothschedule/smoothschedule/scheduling/schedule/migrations/0008_create_default_resource_types.py diff --git a/smoothschedule/schedule/migrations/0009_add_service_display_order.py b/smoothschedule/smoothschedule/scheduling/schedule/migrations/0009_add_service_display_order.py similarity index 100% rename from smoothschedule/schedule/migrations/0009_add_service_display_order.py rename to smoothschedule/smoothschedule/scheduling/schedule/migrations/0009_add_service_display_order.py diff --git a/smoothschedule/schedule/migrations/0010_add_resourcetype_description_photos.py b/smoothschedule/smoothschedule/scheduling/schedule/migrations/0010_add_resourcetype_description_photos.py similarity index 100% rename from smoothschedule/schedule/migrations/0010_add_resourcetype_description_photos.py rename to smoothschedule/smoothschedule/scheduling/schedule/migrations/0010_add_resourcetype_description_photos.py diff --git a/smoothschedule/schedule/migrations/0011_add_photos_to_service.py b/smoothschedule/smoothschedule/scheduling/schedule/migrations/0011_add_photos_to_service.py similarity index 100% rename from smoothschedule/schedule/migrations/0011_add_photos_to_service.py rename to smoothschedule/smoothschedule/scheduling/schedule/migrations/0011_add_photos_to_service.py diff --git a/smoothschedule/schedule/migrations/0012_remove_photos_from_resourcetype.py b/smoothschedule/smoothschedule/scheduling/schedule/migrations/0012_remove_photos_from_resourcetype.py similarity index 100% rename from smoothschedule/schedule/migrations/0012_remove_photos_from_resourcetype.py rename to smoothschedule/smoothschedule/scheduling/schedule/migrations/0012_remove_photos_from_resourcetype.py diff --git a/smoothschedule/schedule/migrations/0013_scheduledtask_taskexecutionlog_and_more.py b/smoothschedule/smoothschedule/scheduling/schedule/migrations/0013_scheduledtask_taskexecutionlog_and_more.py similarity index 100% rename from smoothschedule/schedule/migrations/0013_scheduledtask_taskexecutionlog_and_more.py rename to smoothschedule/smoothschedule/scheduling/schedule/migrations/0013_scheduledtask_taskexecutionlog_and_more.py diff --git a/smoothschedule/schedule/migrations/0014_whitelistedurl.py b/smoothschedule/smoothschedule/scheduling/schedule/migrations/0014_whitelistedurl.py similarity index 100% rename from smoothschedule/schedule/migrations/0014_whitelistedurl.py rename to smoothschedule/smoothschedule/scheduling/schedule/migrations/0014_whitelistedurl.py diff --git a/smoothschedule/schedule/migrations/0015_scheduledtask_plugin_code_plugintemplate_and_more.py b/smoothschedule/smoothschedule/scheduling/schedule/migrations/0015_scheduledtask_plugin_code_plugintemplate_and_more.py similarity index 100% rename from smoothschedule/schedule/migrations/0015_scheduledtask_plugin_code_plugintemplate_and_more.py rename to smoothschedule/smoothschedule/scheduling/schedule/migrations/0015_scheduledtask_plugin_code_plugintemplate_and_more.py diff --git a/smoothschedule/schedule/migrations/0016_plugintemplate_version.py b/smoothschedule/smoothschedule/scheduling/schedule/migrations/0016_plugintemplate_version.py similarity index 100% rename from smoothschedule/schedule/migrations/0016_plugintemplate_version.py rename to smoothschedule/smoothschedule/scheduling/schedule/migrations/0016_plugintemplate_version.py diff --git a/smoothschedule/schedule/migrations/0017_plugintemplate_logo_url.py b/smoothschedule/smoothschedule/scheduling/schedule/migrations/0017_plugintemplate_logo_url.py similarity index 100% rename from smoothschedule/schedule/migrations/0017_plugintemplate_logo_url.py rename to smoothschedule/smoothschedule/scheduling/schedule/migrations/0017_plugintemplate_logo_url.py diff --git a/smoothschedule/schedule/migrations/0018_alter_plugininstallation_scheduled_task.py b/smoothschedule/smoothschedule/scheduling/schedule/migrations/0018_alter_plugininstallation_scheduled_task.py similarity index 100% rename from smoothschedule/schedule/migrations/0018_alter_plugininstallation_scheduled_task.py rename to smoothschedule/smoothschedule/scheduling/schedule/migrations/0018_alter_plugininstallation_scheduled_task.py diff --git a/smoothschedule/schedule/migrations/0019_alter_event_status_eventplugin_event_plugins.py b/smoothschedule/smoothschedule/scheduling/schedule/migrations/0019_alter_event_status_eventplugin_event_plugins.py similarity index 100% rename from smoothschedule/schedule/migrations/0019_alter_event_status_eventplugin_event_plugins.py rename to smoothschedule/smoothschedule/scheduling/schedule/migrations/0019_alter_event_status_eventplugin_event_plugins.py diff --git a/smoothschedule/schedule/migrations/0020_add_eventplugin_offset.py b/smoothschedule/smoothschedule/scheduling/schedule/migrations/0020_add_eventplugin_offset.py similarity index 100% rename from smoothschedule/schedule/migrations/0020_add_eventplugin_offset.py rename to smoothschedule/smoothschedule/scheduling/schedule/migrations/0020_add_eventplugin_offset.py diff --git a/smoothschedule/schedule/migrations/0021_add_global_event_plugin.py b/smoothschedule/smoothschedule/scheduling/schedule/migrations/0021_add_global_event_plugin.py similarity index 100% rename from smoothschedule/schedule/migrations/0021_add_global_event_plugin.py rename to smoothschedule/smoothschedule/scheduling/schedule/migrations/0021_add_global_event_plugin.py diff --git a/smoothschedule/schedule/migrations/0022_add_apply_to_existing_flag.py b/smoothschedule/smoothschedule/scheduling/schedule/migrations/0022_add_apply_to_existing_flag.py similarity index 100% rename from smoothschedule/schedule/migrations/0022_add_apply_to_existing_flag.py rename to smoothschedule/smoothschedule/scheduling/schedule/migrations/0022_add_apply_to_existing_flag.py diff --git a/smoothschedule/schedule/migrations/0023_email_template.py b/smoothschedule/smoothschedule/scheduling/schedule/migrations/0023_email_template.py similarity index 100% rename from smoothschedule/schedule/migrations/0023_email_template.py rename to smoothschedule/smoothschedule/scheduling/schedule/migrations/0023_email_template.py diff --git a/smoothschedule/schedule/migrations/0024_resource_archived_by_quota_at_and_more.py b/smoothschedule/smoothschedule/scheduling/schedule/migrations/0024_resource_archived_by_quota_at_and_more.py similarity index 100% rename from smoothschedule/schedule/migrations/0024_resource_archived_by_quota_at_and_more.py rename to smoothschedule/smoothschedule/scheduling/schedule/migrations/0024_resource_archived_by_quota_at_and_more.py diff --git a/smoothschedule/schedule/migrations/0025_add_variable_pricing.py b/smoothschedule/smoothschedule/scheduling/schedule/migrations/0025_add_variable_pricing.py similarity index 100% rename from smoothschedule/schedule/migrations/0025_add_variable_pricing.py rename to smoothschedule/smoothschedule/scheduling/schedule/migrations/0025_add_variable_pricing.py diff --git a/smoothschedule/schedule/migrations/0026_simplify_deposit_fields.py b/smoothschedule/smoothschedule/scheduling/schedule/migrations/0026_simplify_deposit_fields.py similarity index 100% rename from smoothschedule/schedule/migrations/0026_simplify_deposit_fields.py rename to smoothschedule/smoothschedule/scheduling/schedule/migrations/0026_simplify_deposit_fields.py diff --git a/smoothschedule/schedule/migrations/0027_add_deposit_percent_back.py b/smoothschedule/smoothschedule/scheduling/schedule/migrations/0027_add_deposit_percent_back.py similarity index 100% rename from smoothschedule/schedule/migrations/0027_add_deposit_percent_back.py rename to smoothschedule/smoothschedule/scheduling/schedule/migrations/0027_add_deposit_percent_back.py diff --git a/smoothschedule/schedule/migrations/0028_add_timeblock_and_holiday.py b/smoothschedule/smoothschedule/scheduling/schedule/migrations/0028_add_timeblock_and_holiday.py similarity index 100% rename from smoothschedule/schedule/migrations/0028_add_timeblock_and_holiday.py rename to smoothschedule/smoothschedule/scheduling/schedule/migrations/0028_add_timeblock_and_holiday.py diff --git a/smoothschedule/schedule/migrations/0029_add_user_can_edit_schedule.py b/smoothschedule/smoothschedule/scheduling/schedule/migrations/0029_add_user_can_edit_schedule.py similarity index 100% rename from smoothschedule/schedule/migrations/0029_add_user_can_edit_schedule.py rename to smoothschedule/smoothschedule/scheduling/schedule/migrations/0029_add_user_can_edit_schedule.py diff --git a/smoothschedule/schedule/migrations/0030_time_block_approval.py b/smoothschedule/smoothschedule/scheduling/schedule/migrations/0030_time_block_approval.py similarity index 100% rename from smoothschedule/schedule/migrations/0030_time_block_approval.py rename to smoothschedule/smoothschedule/scheduling/schedule/migrations/0030_time_block_approval.py diff --git a/smoothschedule/smoothschedule/scheduling/schedule/migrations/__init__.py b/smoothschedule/smoothschedule/scheduling/schedule/migrations/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/smoothschedule/schedule/models.py b/smoothschedule/smoothschedule/scheduling/schedule/models.py similarity index 99% rename from smoothschedule/schedule/models.py rename to smoothschedule/smoothschedule/scheduling/schedule/models.py index 81c59d3..af8b0cf 100644 --- a/smoothschedule/schedule/models.py +++ b/smoothschedule/smoothschedule/scheduling/schedule/models.py @@ -74,6 +74,7 @@ class Service(models.Model): updated_at = models.DateTimeField(auto_now=True) class Meta: + app_label = 'schedule' ordering = ['display_order', 'name'] indexes = [models.Index(fields=['is_active', 'display_order'])] @@ -136,6 +137,7 @@ class ResourceType(models.Model): updated_at = models.DateTimeField(auto_now=True) class Meta: + app_label = 'schedule' ordering = ['name'] indexes = [models.Index(fields=['category', 'name'])] @@ -237,6 +239,7 @@ class Resource(models.Model): ) class Meta: + app_label = 'schedule' ordering = ['name'] indexes = [models.Index(fields=['is_active', 'name'])] @@ -315,6 +318,7 @@ class Event(models.Model): ) class Meta: + app_label = 'schedule' ordering = ['start_time'] indexes = [ models.Index(fields=['start_time', 'end_time']), @@ -465,6 +469,7 @@ class EventPlugin(models.Model): created_at = models.DateTimeField(auto_now_add=True) class Meta: + app_label = 'schedule' ordering = ['execution_order', 'created_at'] # Allow same plugin with different triggers, but not duplicate trigger+offset unique_together = ['event', 'plugin_installation', 'trigger', 'offset_minutes'] @@ -544,6 +549,7 @@ class GlobalEventPlugin(models.Model): ) class Meta: + app_label = 'schedule' ordering = ['execution_order', 'created_at'] # Prevent duplicate rules unique_together = ['plugin_installation', 'trigger', 'offset_minutes'] @@ -612,6 +618,7 @@ class Participant(models.Model): created_at = models.DateTimeField(auto_now_add=True) class Meta: + app_label = 'schedule' unique_together = ['event', 'content_type', 'object_id'] indexes = [ models.Index(fields=['event', 'role']), @@ -733,6 +740,7 @@ class ScheduledTask(models.Model): ) class Meta: + app_label = 'schedule' ordering = ['-created_at'] indexes = [ models.Index(fields=['status', 'next_run_at']), @@ -824,6 +832,7 @@ class TaskExecutionLog(models.Model): ) class Meta: + app_label = 'schedule' ordering = ['-started_at'] indexes = [ models.Index(fields=['scheduled_task', '-started_at']), @@ -914,6 +923,7 @@ class WhitelistedURL(models.Model): ) class Meta: + app_label = 'schedule' ordering = ['-created_at'] indexes = [ models.Index(fields=['domain', 'is_active']), @@ -1184,6 +1194,7 @@ class PluginTemplate(models.Model): ) class Meta: + app_label = 'schedule' ordering = ['-created_at'] indexes = [ models.Index(fields=['visibility', 'is_approved', '-install_count']), @@ -1318,6 +1329,7 @@ class PluginInstallation(models.Model): ) class Meta: + app_label = 'schedule' ordering = ['-installed_at'] indexes = [ models.Index(fields=['template', '-installed_at']), @@ -1427,6 +1439,7 @@ class EmailTemplate(models.Model): updated_at = models.DateTimeField(auto_now=True) class Meta: + app_label = 'schedule' ordering = ['name'] indexes = [ models.Index(fields=['scope', 'category']), @@ -1557,6 +1570,7 @@ class Holiday(models.Model): is_active = models.BooleanField(default=True) class Meta: + app_label = 'schedule' ordering = ['country', 'name'] indexes = [ models.Index(fields=['country', 'is_active']), @@ -1797,6 +1811,7 @@ class TimeBlock(models.Model): updated_at = models.DateTimeField(auto_now=True) class Meta: + app_label = 'schedule' ordering = ['-created_at'] indexes = [ models.Index(fields=['resource', 'is_active']), diff --git a/smoothschedule/schedule/plugins.py b/smoothschedule/smoothschedule/scheduling/schedule/plugins.py similarity index 100% rename from smoothschedule/schedule/plugins.py rename to smoothschedule/smoothschedule/scheduling/schedule/plugins.py diff --git a/smoothschedule/schedule/routing.py b/smoothschedule/smoothschedule/scheduling/schedule/routing.py similarity index 100% rename from smoothschedule/schedule/routing.py rename to smoothschedule/smoothschedule/scheduling/schedule/routing.py diff --git a/smoothschedule/schedule/safe_scripting.py b/smoothschedule/smoothschedule/scheduling/schedule/safe_scripting.py similarity index 99% rename from smoothschedule/schedule/safe_scripting.py rename to smoothschedule/smoothschedule/scheduling/schedule/safe_scripting.py index e335d17..088cfab 100644 --- a/smoothschedule/schedule/safe_scripting.py +++ b/smoothschedule/smoothschedule/scheduling/schedule/safe_scripting.py @@ -117,7 +117,7 @@ class SafeScriptAPI: """ self._check_api_limit() - from smoothschedule.users.models import User + from smoothschedule.identity.users.models import User queryset = User.objects.filter(role='customer') @@ -159,7 +159,7 @@ class SafeScriptAPI: # Resolve customer ID to email if needed if isinstance(to, int): - from smoothschedule.users.models import User + from smoothschedule.identity.users.models import User try: user = User.objects.get(id=to) to = user.email diff --git a/smoothschedule/schedule/serializers.py b/smoothschedule/smoothschedule/scheduling/schedule/serializers.py similarity index 99% rename from smoothschedule/schedule/serializers.py rename to smoothschedule/smoothschedule/scheduling/schedule/serializers.py index a8f3166..c0a58f1 100644 --- a/smoothschedule/schedule/serializers.py +++ b/smoothschedule/smoothschedule/scheduling/schedule/serializers.py @@ -6,7 +6,7 @@ from django.contrib.contenttypes.models import ContentType from django.core.exceptions import ValidationError as DjangoValidationError from .models import Resource, Event, Participant, Service, ResourceType, ScheduledTask, TaskExecutionLog, PluginTemplate, PluginInstallation, EventPlugin, GlobalEventPlugin, EmailTemplate, Holiday, TimeBlock from .services import AvailabilityService -from smoothschedule.users.models import User +from smoothschedule.identity.users.models import User class ResourceTypeSerializer(serializers.ModelSerializer): @@ -551,7 +551,7 @@ class EventSerializer(serializers.ModelSerializer): ) # Create Staff participants - from smoothschedule.users.models import User + from smoothschedule.identity.users.models import User user_content_type = ContentType.objects.get_for_model(User) for staff_id in staff_ids: Participant.objects.create( diff --git a/smoothschedule/schedule/services.py b/smoothschedule/smoothschedule/scheduling/schedule/services.py similarity index 100% rename from smoothschedule/schedule/services.py rename to smoothschedule/smoothschedule/scheduling/schedule/services.py diff --git a/smoothschedule/schedule/signals.py b/smoothschedule/smoothschedule/scheduling/schedule/signals.py similarity index 98% rename from smoothschedule/schedule/signals.py rename to smoothschedule/smoothschedule/scheduling/schedule/signals.py index 6cd4fa6..c034e27 100644 --- a/smoothschedule/schedule/signals.py +++ b/smoothschedule/smoothschedule/scheduling/schedule/signals.py @@ -482,7 +482,7 @@ def send_customer_notification_task(sender, event, notification_type, tenant, ** Can be replaced or supplemented by custom handlers. """ try: - from smoothschedule.field_mobile.tasks import send_customer_status_notification + from smoothschedule.communication.mobile.tasks import send_customer_status_notification send_customer_status_notification.delay( tenant_id=tenant.id, @@ -537,7 +537,7 @@ time_off_request_submitted = Signal() def is_notifications_available(): """Check if the notifications app is installed and migrated.""" try: - from notifications.models import Notification + from smoothschedule.communication.notifications.models import Notification Notification.objects.exists() return True except Exception: @@ -551,7 +551,7 @@ def create_notification_safe(recipient, actor, verb, action_object=None, target= return None try: - from notifications.models import Notification + from smoothschedule.communication.notifications.models import Notification return Notification.objects.create( recipient=recipient, actor=actor, @@ -595,7 +595,7 @@ def notify_managers_on_pending_time_off(sender, instance, created, **kwargs): ) # Find all managers and owners to notify - from smoothschedule.users.models import User + from smoothschedule.identity.users.models import User reviewers = User.objects.filter( role__in=[User.Role.TENANT_OWNER, User.Role.TENANT_MANAGER], diff --git a/smoothschedule/schedule/tasks.py b/smoothschedule/smoothschedule/scheduling/schedule/tasks.py similarity index 100% rename from smoothschedule/schedule/tasks.py rename to smoothschedule/smoothschedule/scheduling/schedule/tasks.py diff --git a/smoothschedule/schedule/template_parser.py b/smoothschedule/smoothschedule/scheduling/schedule/template_parser.py similarity index 100% rename from smoothschedule/schedule/template_parser.py rename to smoothschedule/smoothschedule/scheduling/schedule/template_parser.py diff --git a/smoothschedule/schedule/templates/schedule/emails/appointment_reminder.html b/smoothschedule/smoothschedule/scheduling/schedule/templates/schedule/emails/appointment_reminder.html similarity index 100% rename from smoothschedule/schedule/templates/schedule/emails/appointment_reminder.html rename to smoothschedule/smoothschedule/scheduling/schedule/templates/schedule/emails/appointment_reminder.html diff --git a/smoothschedule/schedule/test_export.py b/smoothschedule/smoothschedule/scheduling/schedule/test_export.py similarity index 97% rename from smoothschedule/schedule/test_export.py rename to smoothschedule/smoothschedule/scheduling/schedule/test_export.py index 9d90bbb..498a765 100644 --- a/smoothschedule/schedule/test_export.py +++ b/smoothschedule/smoothschedule/scheduling/schedule/test_export.py @@ -8,9 +8,9 @@ from django.test import TestCase, Client from django.contrib.auth import get_user_model from django.utils import timezone from datetime import timedelta -from core.models import Tenant, Domain -from schedule.models import Event, Resource, Service -from smoothschedule.users.models import User as CustomUser +from smoothschedule.identity.core.models import Tenant, Domain +from smoothschedule.scheduling.schedule.models import Event, Resource, Service +from smoothschedule.identity.users.models import User as CustomUser User = get_user_model() diff --git a/smoothschedule/tickets/tests.py b/smoothschedule/smoothschedule/scheduling/schedule/tests.py similarity index 100% rename from smoothschedule/tickets/tests.py rename to smoothschedule/smoothschedule/scheduling/schedule/tests.py diff --git a/smoothschedule/schedule/tests/test_calendar_sync_permissions.py b/smoothschedule/smoothschedule/scheduling/schedule/tests/test_calendar_sync_permissions.py similarity index 99% rename from smoothschedule/schedule/tests/test_calendar_sync_permissions.py rename to smoothschedule/smoothschedule/scheduling/schedule/tests/test_calendar_sync_permissions.py index 7bac48b..6644246 100644 --- a/smoothschedule/schedule/tests/test_calendar_sync_permissions.py +++ b/smoothschedule/smoothschedule/scheduling/schedule/tests/test_calendar_sync_permissions.py @@ -12,8 +12,8 @@ Includes tests for: from django.test import TestCase from rest_framework.test import APITestCase, APIClient from rest_framework import status -from core.models import Tenant, OAuthCredential -from smoothschedule.users.models import User +from smoothschedule.identity.core.models import Tenant, OAuthCredential +from smoothschedule.identity.users.models import User class CalendarSyncPermissionTests(APITestCase): diff --git a/smoothschedule/schedule/urls.py b/smoothschedule/smoothschedule/scheduling/schedule/urls.py similarity index 100% rename from smoothschedule/schedule/urls.py rename to smoothschedule/smoothschedule/scheduling/schedule/urls.py diff --git a/smoothschedule/schedule/views.py b/smoothschedule/smoothschedule/scheduling/schedule/views.py similarity index 99% rename from smoothschedule/schedule/views.py rename to smoothschedule/smoothschedule/scheduling/schedule/views.py index 4c2c474..8eff350 100644 --- a/smoothschedule/schedule/views.py +++ b/smoothschedule/smoothschedule/scheduling/schedule/views.py @@ -10,7 +10,7 @@ from rest_framework.decorators import action from rest_framework.exceptions import PermissionDenied from django.core.exceptions import ValidationError as DjangoValidationError from django.contrib.contenttypes.models import ContentType -from notifications.models import Notification +from smoothschedule.communication.notifications.models import Notification from .models import Resource, Event, Participant, ResourceType, ScheduledTask, TaskExecutionLog, PluginTemplate, PluginInstallation, EventPlugin, GlobalEventPlugin, EmailTemplate, Holiday, TimeBlock from .serializers import ( ResourceSerializer, EventSerializer, ParticipantSerializer, @@ -23,8 +23,8 @@ from .serializers import ( TimeBlockSerializer, TimeBlockListSerializer, BlockedDateSerializer, CheckConflictsSerializer ) from .models import Service -from core.permissions import HasQuota -from core.mixins import ( +from smoothschedule.identity.core.permissions import HasQuota +from smoothschedule.identity.core.mixins import ( TenantFilteredQuerySetMixin, SandboxFilteredQuerySetMixin, UserTenantFilteredMixin, @@ -34,7 +34,7 @@ from core.mixins import ( PluginFeatureRequiredMixin, TaskFeatureRequiredMixin, ) -from smoothschedule.users.models import User +from smoothschedule.identity.users.models import User class ResourceTypeViewSet(viewsets.ModelViewSet): @@ -113,7 +113,7 @@ class ResourceViewSet(TenantFilteredQuerySetMixin, viewsets.ModelViewSet): Returns the most recent location update for the user linked to this resource, along with their current job status (if any). """ - from smoothschedule.field_mobile.models import EmployeeLocationUpdate + from smoothschedule.communication.mobile.models import EmployeeLocationUpdate from django.contrib.contenttypes.models import ContentType resource = self.get_object() @@ -376,8 +376,8 @@ class EventViewSet(TenantFilteredQuerySetMixin, viewsets.ModelViewSet): Validates the status transition using StatusMachine rules. Records status change in history and optionally triggers customer notifications. """ - from smoothschedule.field_mobile.services import StatusMachine - from smoothschedule.field_mobile.services.status_machine import StatusTransitionError + from smoothschedule.communication.mobile.services import StatusMachine + from smoothschedule.communication.mobile.services.status_machine import StatusTransitionError event = self.get_object() tenant = getattr(request, 'tenant', None) @@ -441,8 +441,8 @@ class EventViewSet(TenantFilteredQuerySetMixin, viewsets.ModelViewSet): Changes status to EN_ROUTE and optionally notifies customer. """ - from smoothschedule.field_mobile.services import StatusMachine - from smoothschedule.field_mobile.services.status_machine import StatusTransitionError + from smoothschedule.communication.mobile.services import StatusMachine + from smoothschedule.communication.mobile.services.status_machine import StatusTransitionError event = self.get_object() tenant = getattr(request, 'tenant', None) @@ -491,7 +491,7 @@ class EventViewSet(TenantFilteredQuerySetMixin, viewsets.ModelViewSet): Returns list of status changes with timestamps and who made them. """ - from smoothschedule.field_mobile.models import EventStatusHistory + from smoothschedule.communication.mobile.models import EventStatusHistory event = self.get_object() tenant = getattr(request, 'tenant', None) @@ -533,7 +533,7 @@ class EventViewSet(TenantFilteredQuerySetMixin, viewsets.ModelViewSet): Returns list of statuses the event can transition to. """ - from smoothschedule.field_mobile.services import StatusMachine + from smoothschedule.communication.mobile.services import StatusMachine event = self.get_object() tenant = getattr(request, 'tenant', None)