"""Fixtures de pruebas del módulo CRM. Las pruebas de servicios corren contra SQLite en memoria usando ``schema_translate_map`` para mapear los schemas ``crm``/``core`` al schema principal de SQLite. Esto permite ejercitar la lógica de negocio sin depender de PostgreSQL/Docker en el entorno de desarrollo local. Nota: la validación estructural del esquema (FKs cross-schema, DDL) se hace con la migración Alembic contra PostgreSQL en CI (``TEST_DATABASE_URL``). """ import os import sys from datetime import datetime import pytest from sqlalchemy import Column, Integer, String, Table, create_engine, event from sqlalchemy.orm import sessionmaker from sqlalchemy.pool import StaticPool BACKEND_DIR = os.path.abspath(os.path.join(os.path.dirname(__file__), "..")) if BACKEND_DIR not in sys.path: sys.path.insert(0, BACKEND_DIR) from core.database import Base # noqa: E402 # Importar los modelos registra sus tablas en Base.metadata import api.v1.modules.crm.accounts.models # noqa: E402,F401 import api.v1.modules.crm.activities.models # noqa: E402,F401 import api.v1.modules.crm.addresses.models # noqa: E402,F401 import api.v1.modules.crm.contacts.models # noqa: E402,F401 import api.v1.modules.crm.documents.models # noqa: E402,F401 import api.v1.modules.crm.leads.models # noqa: E402,F401 import api.v1.modules.crm.opportunities.models # noqa: E402,F401 import api.v1.modules.crm.pipelines.models # noqa: E402,F401 import api.v1.modules.crm.quotes.models # noqa: E402,F401 import api.v1.modules.crm.service_requests.models # noqa: E402,F401 import api.v1.modules.crm.suppliers.models # noqa: E402,F401 import api.v1.modules.ops.shipments.models # noqa: E402,F401 _SCHEMA_MAP = {"crm": None, "core": None, "ops": None} # Tabla mínima core.tenants para resolver la FK tenant_id de las tablas crm. # En CI (PostgreSQL) la tabla real la crea la migración inicial del core. if "core.tenants" not in Base.metadata.tables: Table( "tenants", Base.metadata, Column("id", Integer, primary_key=True), Column("name", String(255)), schema="core", ) TENANT_ID = 1 COMPANY_ID = 1 @pytest.fixture() def db(): engine = create_engine( "sqlite://", connect_args={"check_same_thread": False}, poolclass=StaticPool, future=True, ).execution_options(schema_translate_map=_SCHEMA_MAP) @event.listens_for(engine, "connect") def _register_now(dbapi_conn, _record): # Soporta server_default text("now()") de los mixins de timestamp dbapi_conn.create_function( "now", 0, lambda: datetime.utcnow().strftime("%Y-%m-%d %H:%M:%S.%f") ) Base.metadata.create_all(engine) session_factory = sessionmaker(bind=engine, future=True) session = session_factory() try: yield session finally: session.close() engine.dispose()