fix error in gitignore

This commit is contained in:
2026-09-24 12:32:59 +03:30
commit 86c117ee2a
165 changed files with 5963 additions and 0 deletions
+5
View File
@@ -0,0 +1,5 @@
try:
from .celery import app as celery_app
__all__ = ("celery_app",)
except Exception: # celery is optional for basic dev runs
celery_app = None
+7
View File
@@ -0,0 +1,7 @@
import os
from django.core.asgi import get_asgi_application
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "config.settings")
application = get_asgi_application()
+9
View File
@@ -0,0 +1,9 @@
import os
from celery import Celery
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "config.settings")
app = Celery("cetana")
app.config_from_object("django.conf:settings", namespace="CELERY")
app.autodiscover_tasks()
+209
View File
@@ -0,0 +1,209 @@
"""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", "")
+32
View File
@@ -0,0 +1,32 @@
"""Root URL configuration for the Cetana backend."""
from django.contrib import admin
from django.urls import include, path
from drf_spectacular.views import SpectacularAPIView, SpectacularSwaggerView
from rest_framework.routers import DefaultRouter
from apps.accounts.views import UserViewSet
from apps.core.views import SettingsView, TestOdooView
from apps.rbac.views import RoleViewSet
router = DefaultRouter()
router.register("users", UserViewSet, basename="user")
router.register("roles", RoleViewSet, basename="role")
urlpatterns = [
path("admin/", admin.site.urls),
path("api/v1/auth/", include("apps.accounts.urls")),
path("api/v1/workflows/", include("apps.workflows.urls")),
path("api/v1/reservations/", include("apps.reservations.urls")),
path("api/v1/orders/", include("apps.orders.urls")),
path("api/v1/processing/", include("apps.processing.urls")),
path("api/v1/payments/", include("apps.payments.urls")),
path("api/v1/invoices/", include("apps.invoicing.urls")),
path("api/v1/audit/", include("apps.audit.urls")),
path("api/v1/reports/", include("apps.reports.urls")),
path("api/v1/live-monitoring/", include("apps.live_monitoring.urls")),
path("api/v1/settings/", SettingsView.as_view(), name="settings"),
path("api/v1/settings/test-odoo/", TestOdooView.as_view(), name="settings-test-odoo"),
path("api/v1/", include(router.urls)),
path("api/v1/schema/", SpectacularAPIView.as_view(), name="schema"),
path("api/v1/docs/", SpectacularSwaggerView.as_view(url_name="schema"), name="swagger-ui"),
]
+7
View File
@@ -0,0 +1,7 @@
import os
from django.core.wsgi import get_wsgi_application
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "config.settings")
application = get_wsgi_application()