"""Django settings for the Cetana backend. All secrets and environment-specific values are read from environment variables (optionally loaded from a local .env file). Never commit secrets. """ import os from pathlib import Path BASE_DIR = Path(__file__).resolve().parent.parent # Best-effort .env loading (dependency-free path; python-dotenv used when available). try: from dotenv import load_dotenv load_dotenv(BASE_DIR / ".env") except Exception: # pragma: no cover - dotenv is optional pass def env(name: str, default: str = "") -> str: return os.environ.get(name, default) def env_bool(name: str, default: bool = False) -> bool: val = os.environ.get(name) if val is None: return default return val.lower() in {"1", "true", "yes", "on"} SECRET_KEY = env("SECRET_KEY", "insecure-dev-key-change-me") DEBUG = env_bool("DEBUG", True) ALLOWED_HOSTS = [h.strip() for h in env("ALLOWED_HOSTS", "localhost,127.0.0.1").split(",") if h.strip()] # --------------------------------------------------------------------------- # Database # --------------------------------------------------------------------------- DATABASE_URL = env("DATABASE_URL", "") if DATABASE_URL.startswith("postgres"): import urllib.parse _url = urllib.parse.urlparse(DATABASE_URL) DATABASES = { "default": { "ENGINE": "django.db.backends.postgresql", "NAME": _url.path.lstrip("/") or "cetana", "USER": _url.username or "", "PASSWORD": _url.password or "", "HOST": _url.hostname or "localhost", "PORT": _url.port or 5432, } } else: DATABASES = { "default": { "ENGINE": "django.db.backends.sqlite3", "NAME": BASE_DIR / "db.sqlite3", } } # --------------------------------------------------------------------------- # Applications # --------------------------------------------------------------------------- INSTALLED_APPS = [ "django.contrib.admin", "django.contrib.auth", "django.contrib.contenttypes", "django.contrib.sessions", "django.contrib.messages", "django.contrib.staticfiles", # third-party "rest_framework", "rest_framework_simplejwt", "corsheaders", "django_filters", "drf_spectacular", # local "apps.core", "apps.accounts", "apps.rbac", "apps.reservations", "apps.orders", "apps.workflows", "apps.processing", "apps.pricing", "apps.payments", "apps.invoicing", "apps.notifications", "apps.reports", "apps.live_monitoring", "apps.audit", ] MIDDLEWARE = [ "corsheaders.middleware.CorsMiddleware", "django.middleware.security.SecurityMiddleware", "django.contrib.sessions.middleware.SessionMiddleware", "django.middleware.common.CommonMiddleware", "django.middleware.csrf.CsrfViewMiddleware", "django.contrib.auth.middleware.AuthenticationMiddleware", "django.contrib.messages.middleware.MessageMiddleware", "django.middleware.clickjacking.XFrameOptionsMiddleware", ] ROOT_URLCONF = "config.urls" TEMPLATES = [ { "BACKEND": "django.template.backends.django.DjangoTemplates", "DIRS": [], "APP_DIRS": True, "OPTIONS": { "context_processors": [ "django.template.context_processors.debug", "django.template.context_processors.request", "django.contrib.auth.context_processors.auth", "django.contrib.messages.context_processors.messages", ], }, }, ] WSGI_APPLICATION = "config.wsgi.application" ASGI_APPLICATION = "config.asgi.application" AUTH_USER_MODEL = "accounts.User" AUTH_PASSWORD_VALIDATORS = [ {"NAME": "django.contrib.auth.password_validation.UserAttributeSimilarityValidator"}, {"NAME": "django.contrib.auth.password_validation.MinimumLengthValidator"}, {"NAME": "django.contrib.auth.password_validation.CommonPasswordValidator"}, {"NAME": "django.contrib.auth.password_validation.NumericPasswordValidator"}, ] LANGUAGE_CODE = "en-us" TIME_ZONE = "UTC" USE_I18N = True USE_TZ = True STATIC_URL = "static/" STATIC_ROOT = BASE_DIR / "staticfiles" MEDIA_URL = "media/" MEDIA_ROOT = BASE_DIR / "media" DEFAULT_AUTO_FIELD = "django.db.models.BigAutoField" # --------------------------------------------------------------------------- # DRF # --------------------------------------------------------------------------- REST_FRAMEWORK = { "DEFAULT_AUTHENTICATION_CLASSES": ( "rest_framework_simplejwt.authentication.JWTAuthentication", ), "DEFAULT_PERMISSION_CLASSES": ("rest_framework.permissions.IsAuthenticated",), "DEFAULT_FILTER_BACKENDS": ("django_filters.rest_framework.DjangoFilterBackend",), "DEFAULT_PAGINATION_CLASS": "apps.core.pagination.StandardPagination", "PAGE_SIZE": 20, "DEFAULT_SCHEMA_CLASS": "drf_spectacular.openapi.AutoSchema", "EXCEPTION_HANDLER": "apps.core.errors.api_exception_handler", } SPECTACULAR_SETTINGS = { "TITLE": "Cetana API", "DESCRIPTION": "Configurable pistachio processing reservation & management platform", "VERSION": "1.0.0", "SERVE_INCLUDE_SCHEMA": False, } from datetime import timedelta # noqa: E402 SIMPLE_JWT = { "ACCESS_TOKEN_LIFETIME": timedelta(hours=1), "REFRESH_TOKEN_LIFETIME": timedelta(days=7), "AUTH_HEADER_TYPES": ("Bearer",), } # --------------------------------------------------------------------------- # CORS # --------------------------------------------------------------------------- CORS_ALLOW_ALL_ORIGINS = DEBUG CORS_ALLOWED_ORIGINS = [ o.strip() for o in env("CORS_ALLOWED_ORIGINS", "http://localhost:5173").split(",") if o.strip() ] # --------------------------------------------------------------------------- # Celery # --------------------------------------------------------------------------- CELERY_BROKER_URL = env("CELERY_BROKER_URL", "redis://localhost:6379/0") CELERY_RESULT_BACKEND = CELERY_BROKER_URL CELERY_TASK_ACKS_LATE = True CELERY_TASK_DEFAULT_RETRY_DELAY = 60 CELERY_TASK_MAX_RETRIES = 5 # --------------------------------------------------------------------------- # Cetana settings # --------------------------------------------------------------------------- BASE_CURRENCY = env("BASE_CURRENCY", "IRR") ODOO_URL = env("ODOO_URL", "") ODOO_DATABASE = env("ODOO_DATABASE", "") ODOO_USERNAME = env("ODOO_USERNAME", "") ODOO_PASSWORD = env("ODOO_PASSWORD", "") ODOO_API_KEY = env("ODOO_API_KEY", "") PAYMENT_GATEWAY_PROVIDER = env("PAYMENT_GATEWAY_PROVIDER", "mock") PAYMENT_GATEWAY_MERCHANT_ID = env("PAYMENT_GATEWAY_MERCHANT_ID", "") SMS_PROVIDER = env("SMS_PROVIDER", "mock") SMS_PROVIDER_API_KEY = env("SMS_PROVIDER_API_KEY", "")