modification done to up the project
This commit is contained in:
parent
131f7ad8e8
commit
b793ac859a
37
.env.example
Normal file
37
.env.example
Normal file
@ -0,0 +1,37 @@
|
||||
# Application Settings
|
||||
APP_NAME="AI Detection API"
|
||||
APP_VERSION="1.0.0"
|
||||
DEBUG=True
|
||||
PORT=8000
|
||||
HOST=0.0.0.0
|
||||
|
||||
# Database Settings
|
||||
# For Docker Compose, use 'postgres' as the host. For local, use 'localhost'.
|
||||
DATABASE_URL="postgresql://postgres:postgres@postgres:5432/test_project_db"
|
||||
POSTGRES_USER=postgres
|
||||
POSTGRES_PASSWORD=postgres
|
||||
POSTGRES_DB=test_project_db
|
||||
POSTGRES_PORT=5432
|
||||
|
||||
# Redis Settings
|
||||
# For Docker Compose, use 'redis' as the host. For local, use 'localhost'.
|
||||
REDIS_HOST=redis
|
||||
REDIS_PORT=6379
|
||||
|
||||
# Security Settings
|
||||
# Generate a secure key for production
|
||||
JWT_SECRET="your-super-secret-jwt-key-change-me"
|
||||
JWT_REFRESH_SECRET="your-super-secret-refresh-key-change-me"
|
||||
JWT_ISSUER="ai-detection-app"
|
||||
JWT_AUDIENCE="ai-detection-users"
|
||||
JWT_ACCESS_TOKEN_EXPIRE_MINUTES=30
|
||||
JWT_REFRESH_TOKEN_EXPIRE_DAYS=7
|
||||
|
||||
# RAG / AI Configuration
|
||||
OPENAI_API_KEY="sk-..."
|
||||
ANTHROPIC_API_KEY="xpk-..."
|
||||
EMBEDDING_PROVIDER="huggingface" # "openai" or "huggingface"
|
||||
LLM_PROVIDER="openai" # "openai" or "anthropic"
|
||||
VECTOR_DB_DIR="./chroma_db"
|
||||
RAG_CHUNK_SIZE=1000
|
||||
RAG_CHUNK_OVERLAP=100
|
||||
52
.gitignore
vendored
Normal file
52
.gitignore
vendored
Normal file
@ -0,0 +1,52 @@
|
||||
# Python
|
||||
__pycache__/
|
||||
*.py[cod]
|
||||
*$py.class
|
||||
*.so
|
||||
.Python
|
||||
build/
|
||||
develop-eggs/
|
||||
dist/
|
||||
downloads/
|
||||
eggs/
|
||||
.eggs/
|
||||
lib/
|
||||
lib64/
|
||||
parts/
|
||||
sdist/
|
||||
var/
|
||||
wheels/
|
||||
share/python-wheels/
|
||||
*.egg-info/
|
||||
.installed.cfg
|
||||
*.egg
|
||||
MANIFEST
|
||||
|
||||
# Environment
|
||||
.env
|
||||
.venv
|
||||
env/
|
||||
venv/
|
||||
ENV/
|
||||
env.bak/
|
||||
venv.bak/
|
||||
|
||||
# Project Specific
|
||||
chroma_db/
|
||||
*.log
|
||||
.pytest_cache/
|
||||
test_results/
|
||||
|
||||
# Editor/IDE
|
||||
.vscode/
|
||||
.idea/
|
||||
*.swp
|
||||
*.swo
|
||||
|
||||
# Docker
|
||||
.docker/
|
||||
docker-compose.override.yml
|
||||
|
||||
# OS
|
||||
.DS_Store
|
||||
Thumbs.db
|
||||
72
RUNNING.md
Normal file
72
RUNNING.md
Normal file
@ -0,0 +1,72 @@
|
||||
# Running the AI-Detection Project
|
||||
|
||||
This project is a FastAPI-based AI application for detection and RAG (Retrieval-Augmented Generation).
|
||||
|
||||
## Prerequisites
|
||||
- **Python 3.11+** (for local setup)
|
||||
- **Docker and Docker Compose** (for containerized setup - Recommended)
|
||||
- **PostgreSQL** and **Redis** (if running locally)
|
||||
|
||||
---
|
||||
|
||||
## 🚀 Option 1: Running with Docker (Recommended)
|
||||
|
||||
The easiest way to run the project is using Docker Compose, which sets up the application, database, and Redis automatically.
|
||||
|
||||
1. **Configure Environment Variables**:
|
||||
Copy the example environment file and fill in your keys:
|
||||
```bash
|
||||
cp .env.example .env
|
||||
```
|
||||
*Note: Open `.env` and provide your `OPENAI_API_KEY` or `ANTHROPIC_API_KEY` if using AI features.*
|
||||
|
||||
2. **Start the Services**:
|
||||
```bash
|
||||
docker-compose up --build
|
||||
```
|
||||
|
||||
3. **Access the API**:
|
||||
- **API Documentation (Swagger UI)**: [http://localhost:8000/docs](http://localhost:8000/docs)
|
||||
- **Health Check**: [http://localhost:8000/health](http://localhost:8000/health)
|
||||
|
||||
---
|
||||
|
||||
## 🛠️ Option 2: Running Locally
|
||||
|
||||
If you prefer to run the application directly on your machine:
|
||||
|
||||
1. **Create a Virtual Environment**:
|
||||
```bash
|
||||
python -m venv venv
|
||||
source venv/bin/activate # On Windows: venv\Scripts\activate
|
||||
```
|
||||
|
||||
2. **Install Dependencies**:
|
||||
```bash
|
||||
pip install -r requirements.txt
|
||||
```
|
||||
|
||||
3. **Configure Environment Variables**:
|
||||
Copy `.env.example` to `.env` and update the settings:
|
||||
- Set `DATABASE_URL` to point to your local PostgreSQL instance (e.g., `postgresql://user:pass@localhost:5432/dbname`).
|
||||
- Set `REDIS_HOST` to `localhost`.
|
||||
|
||||
4. **Run the Application**:
|
||||
```bash
|
||||
uvicorn main:app --host 0.0.0.0 --port 8000 --reload
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 📂 Project Structure Highlights
|
||||
- `main.py`: Entry point of the FastAPI application.
|
||||
- `src/config/`: Configuration management and startup migrations.
|
||||
- `src/services/`: Core business logic (RAG, JWT, etc.).
|
||||
- `src/migrations/`: Database schema definitions.
|
||||
- `docker-compose.yml`: Multi-container orchestration.
|
||||
|
||||
## 🧪 Testing
|
||||
To run tests, ensure dependencies are installed and run:
|
||||
```bash
|
||||
pytest
|
||||
```
|
||||
9
check_routes.py
Normal file
9
check_routes.py
Normal file
@ -0,0 +1,9 @@
|
||||
from main import app
|
||||
from fastapi.routing import APIRoute
|
||||
|
||||
print("Registered Routes:")
|
||||
for route in app.routes:
|
||||
if isinstance(route, APIRoute):
|
||||
print(f"Path: {route.path} | Methods: {route.methods} | Name: {route.name}")
|
||||
else:
|
||||
print(f"Path: {route.path}")
|
||||
18
fix_routes_async.py
Normal file
18
fix_routes_async.py
Normal file
@ -0,0 +1,18 @@
|
||||
import os
|
||||
from pathlib import Path
|
||||
import re
|
||||
|
||||
def fix_routes():
|
||||
routes_dir = Path("src/routes")
|
||||
for route_file in routes_dir.glob("*_routes.py"):
|
||||
content = route_file.read_text(encoding="utf-8")
|
||||
# Add await to crud.* calls
|
||||
# Matches: db_user = crud.get_by_id(user_id) -> await crud.get_by_id(user_id)
|
||||
# Matches: return crud.create(user_in) -> return await crud.create(user_in)
|
||||
# We need to be careful not to double await
|
||||
content = re.sub(r"(?<!await\s)crud\.(\w+)\(", r"await crud.\1(", content)
|
||||
route_file.write_text(content, encoding="utf-8")
|
||||
print(f"Fixed async/await in {route_file.name}")
|
||||
|
||||
if __name__ == "__main__":
|
||||
fix_routes()
|
||||
11
main.py
11
main.py
@ -3,6 +3,7 @@ FastAPI Application Entry Point
|
||||
Enterprise-grade FastAPI application with proper structure and middleware
|
||||
"""
|
||||
import logging
|
||||
import uvicorn
|
||||
from fastapi import FastAPI
|
||||
from fastapi.middleware.cors import CORSMiddleware
|
||||
from src.config.config import settings
|
||||
@ -44,6 +45,9 @@ app.add_middleware(
|
||||
)
|
||||
|
||||
# Include routers
|
||||
import src.models # Trigger model registration
|
||||
from src.routes.index import router as api_router
|
||||
app.include_router(api_router)
|
||||
|
||||
@app.on_event("startup")
|
||||
async def startup_event():
|
||||
@ -85,3 +89,10 @@ async def health_check():
|
||||
"version": settings.APP_VERSION
|
||||
}
|
||||
|
||||
if __name__ == "__main__":
|
||||
uvicorn.run(
|
||||
"main:app",
|
||||
host=settings.HOST,
|
||||
port=settings.PORT,
|
||||
reload=settings.DEBUG
|
||||
)
|
||||
|
||||
57
mass_fix.py
Normal file
57
mass_fix.py
Normal file
@ -0,0 +1,57 @@
|
||||
import os
|
||||
from pathlib import Path
|
||||
import re
|
||||
|
||||
def fix_models():
|
||||
models_dir = Path("src/models")
|
||||
for model_file in models_dir.glob("*.py"):
|
||||
content = model_file.read_text(encoding="utf-8")
|
||||
# Fix reserved 'metadata' name
|
||||
content = content.replace('metadata = Column(JSON', 'doc_metadata = Column(JSON')
|
||||
model_file.write_text(content, encoding="utf-8")
|
||||
|
||||
def fix_services():
|
||||
services_dir = Path("src/services")
|
||||
for service_file in services_dir.glob("*.py"):
|
||||
content = service_file.read_text(encoding="utf-8")
|
||||
|
||||
# Add basic imports
|
||||
needed_imports = []
|
||||
if " date" in content and "from datetime import date" not in content and "import datetime" not in content:
|
||||
needed_imports.append("from datetime import date")
|
||||
if " datetime" in content and "from datetime import" not in content and "import datetime" not in content:
|
||||
needed_imports.append("from datetime import datetime")
|
||||
if " Decimal" in content and "from decimal import Decimal" not in content:
|
||||
needed_imports.append("from decimal import Decimal")
|
||||
|
||||
if needed_imports:
|
||||
content = "\n".join(needed_imports) + "\n" + content
|
||||
|
||||
# Fix missing model type hints by replacing them with Any
|
||||
# Exclude common types like UUID, int, str, bool, List, Dict, Tuple, Optional
|
||||
def replace_type(match):
|
||||
type_name = match.group(1)
|
||||
if type_name in ["UUID", "int", "str", "bool", "List", "Dict", "Tuple", "Optional", "Any", "None", "float", "bytes"]:
|
||||
return match.group(0)
|
||||
return match.group(0).replace(type_name, "Any")
|
||||
|
||||
content = re.sub(r"-> List\[([A-Z]\w+)\]", replace_type, content)
|
||||
content = re.sub(r"-> ([A-Z]\w+)", replace_type, content)
|
||||
content = re.sub(r": ([A-Z]\w+)", replace_type, content)
|
||||
|
||||
# Standardize CRUD class name
|
||||
content = re.sub(r"class (\w+)Service", r"class \1CRUD", content)
|
||||
|
||||
# Ensure 'Any' is imported
|
||||
if "from typing import" in content:
|
||||
if "Any" not in content:
|
||||
content = content.replace("from typing import", "from typing import Any, ")
|
||||
else:
|
||||
content = "from typing import Any\n" + content
|
||||
|
||||
service_file.write_text(content, encoding="utf-8")
|
||||
print(f"Fixed service {service_file.name}")
|
||||
|
||||
if __name__ == "__main__":
|
||||
fix_models()
|
||||
fix_services()
|
||||
15
requirements.txt
Normal file
15
requirements.txt
Normal file
@ -0,0 +1,15 @@
|
||||
fastapi==0.104.1
|
||||
uvicorn==0.24.0
|
||||
pydantic-settings==2.1.0
|
||||
sqlalchemy==2.0.23
|
||||
psycopg2-binary==2.9.9
|
||||
redis==5.0.1
|
||||
python-jose[cryptography]==3.3.0
|
||||
passlib[bcrypt]==1.7.4
|
||||
openai==1.3.5
|
||||
anthropic==0.5.0
|
||||
pinecone-client
|
||||
weaviate-client
|
||||
python-multipart==0.0.6
|
||||
httpx==0.25.2
|
||||
alembic==1.12.1
|
||||
@ -2,6 +2,7 @@
|
||||
FastAPI Application Configuration
|
||||
Enterprise-grade configuration management using Pydantic Settings
|
||||
"""
|
||||
from pydantic import computed_field, model_validator
|
||||
from pydantic_settings import BaseSettings
|
||||
from typing import List, Optional
|
||||
|
||||
@ -18,18 +19,39 @@ class Settings(BaseSettings):
|
||||
APP_DESCRIPTION: str = "Enterprise FastAPI Application"
|
||||
|
||||
# Database
|
||||
DATABASE_URL: str = "postgresql://user:password@localhost:5432/"
|
||||
DATABASE_URL: Optional[str] = None
|
||||
POSTGRES_USER: str = "billing_user"
|
||||
POSTGRES_PASSWORD: str = "Admin123"
|
||||
POSTGRES_DB: str = "test_project_db"
|
||||
POSTGRES_HOST: str = "localhost"
|
||||
POSTGRES_PORT: int = 5432
|
||||
DB_POOL_SIZE: int = 10
|
||||
DB_MAX_OVERFLOW: int = 20
|
||||
DB_POOL_RECYCLE: int = 3600
|
||||
DB_ECHO: bool = False
|
||||
|
||||
@model_validator(mode='after')
|
||||
def assemble_db_url(self) -> 'Settings':
|
||||
if not self.DATABASE_URL:
|
||||
self.DATABASE_URL = f"postgresql://{self.POSTGRES_USER}:{self.POSTGRES_PASSWORD}@{self.POSTGRES_HOST}:{self.POSTGRES_PORT}/{self.POSTGRES_DB}"
|
||||
return self
|
||||
|
||||
# Redis
|
||||
REDIS_HOST: str = "localhost"
|
||||
REDIS_PORT: int = 6379
|
||||
|
||||
# Server
|
||||
HOST: str = "0.0.0.0"
|
||||
PORT: int = 8000
|
||||
|
||||
# Security
|
||||
SECRET_KEY: str = ""
|
||||
JWT_SECRET: str = ""
|
||||
JWT_REFRESH_SECRET: str = ""
|
||||
JWT_ISSUER: str = "ai-detection-app"
|
||||
JWT_AUDIENCE: str = "ai-detection-users"
|
||||
JWT_ACCESS_TOKEN_EXPIRE_MINUTES: int = 30
|
||||
JWT_REFRESH_TOKEN_EXPIRE_DAYS: int = 7
|
||||
ALGORITHM: str = "HS256"
|
||||
ACCESS_TOKEN_EXPIRE_MINUTES: int = 30
|
||||
REFRESH_TOKEN_EXPIRE_DAYS: int = 7
|
||||
@ -56,6 +78,7 @@ class Settings(BaseSettings):
|
||||
env_file = ".env"
|
||||
env_file_encoding = "utf-8"
|
||||
case_sensitive = False
|
||||
extra = "ignore"
|
||||
|
||||
# Global settings instance
|
||||
settings = Settings()
|
||||
@ -1,5 +1,19 @@
|
||||
from sqlalchemy.orm import Session
|
||||
from src.config.database import SessionLocal, get_db
|
||||
from sqlalchemy import create_engine
|
||||
from sqlalchemy.ext.declarative import declarative_base
|
||||
from sqlalchemy.orm import sessionmaker, Session
|
||||
from src.config.config import settings
|
||||
|
||||
engine = create_engine(
|
||||
settings.DATABASE_URL,
|
||||
pool_pre_ping=True,
|
||||
pool_size=settings.DB_POOL_SIZE,
|
||||
max_overflow=settings.DB_MAX_OVERFLOW,
|
||||
echo=settings.DB_ECHO
|
||||
)
|
||||
|
||||
SessionLocal = sessionmaker(autocommit=False, autoflush=False, bind=engine)
|
||||
|
||||
Base = declarative_base()
|
||||
|
||||
def get_db():
|
||||
"""
|
||||
@ -11,4 +25,3 @@ def get_db():
|
||||
yield db
|
||||
finally:
|
||||
db.close()
|
||||
|
||||
|
||||
@ -6,9 +6,13 @@ import os
|
||||
import sys
|
||||
import logging
|
||||
from pathlib import Path
|
||||
import sqlalchemy as sa
|
||||
from sqlalchemy import create_engine, inspect, MetaData
|
||||
from sqlalchemy.orm import sessionmaker
|
||||
import importlib.util
|
||||
from alembic.runtime.migration import MigrationContext
|
||||
from alembic.operations import Operations
|
||||
import alembic
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
@ -59,19 +63,19 @@ class MigrationManager:
|
||||
if '_migrations' not in tables:
|
||||
# Create migrations tracking table
|
||||
with self.engine.begin() as conn:
|
||||
conn.execute("""
|
||||
conn.execute(sa.text("""
|
||||
CREATE TABLE IF NOT EXISTS _migrations (
|
||||
id SERIAL PRIMARY KEY,
|
||||
migration_name VARCHAR(255) NOT NULL UNIQUE,
|
||||
applied_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
|
||||
)
|
||||
""")
|
||||
"""))
|
||||
logger.info("✅ Created migrations tracking table")
|
||||
return set()
|
||||
|
||||
# Get applied migrations
|
||||
with self.engine.connect() as conn:
|
||||
result = conn.execute("SELECT migration_name FROM _migrations ORDER BY applied_at")
|
||||
result = conn.execute(sa.text("SELECT migration_name FROM _migrations ORDER BY applied_at"))
|
||||
applied = {row[0] for row in result}
|
||||
|
||||
logger.debug(f"📋 Found {len(applied)} previously applied migrations")
|
||||
@ -137,61 +141,25 @@ class MigrationManager:
|
||||
logger.warning(f"⚠️ Migration {migration_file.name} has no upgrade() function")
|
||||
return False
|
||||
|
||||
# Create a mock op object with connection
|
||||
class OpMock:
|
||||
def __init__(self, connection):
|
||||
self.connection = connection
|
||||
|
||||
def create_table(self, name, *args, **kwargs):
|
||||
"""Create a new table"""
|
||||
from sqlalchemy import Table
|
||||
table = Table(name, MetaData(), *args, **kwargs)
|
||||
table.create(self.connection, checkfirst=True)
|
||||
logger.debug(f" 📊 Created table: {name}")
|
||||
|
||||
def create_index(self, name, table, columns, **kwargs):
|
||||
"""Create an index"""
|
||||
try:
|
||||
if isinstance(columns, str):
|
||||
columns = [columns]
|
||||
|
||||
# Build index creation SQL
|
||||
unique_clause = "UNIQUE" if kwargs.get('unique') else ""
|
||||
columns_str = ", ".join(f'"{col}"' for col in columns)
|
||||
index_sql = f'CREATE {unique_clause} INDEX IF NOT EXISTS "{name}" ON "{table}" ({columns_str})'
|
||||
|
||||
self.connection.execute(index_sql)
|
||||
logger.debug(f" 🔑 Created index: {name} on {table}({columns_str})")
|
||||
except Exception as e:
|
||||
logger.warning(f" ⚠️ Could not create index {name}: {e}")
|
||||
|
||||
def add_column(self, table, column):
|
||||
"""Add a column to table"""
|
||||
try:
|
||||
self.connection.execute(f'ALTER TABLE "{table}" ADD COLUMN {column}')
|
||||
logger.debug(f" ➕ Added column to {table}")
|
||||
except Exception as e:
|
||||
logger.warning(f" ⚠️ Could not add column to {table}: {e}")
|
||||
|
||||
def drop_table(self, name):
|
||||
"""Drop a table"""
|
||||
try:
|
||||
self.connection.execute(f'DROP TABLE IF EXISTS "{name}"')
|
||||
logger.debug(f" 🗑️ Dropped table: {name}")
|
||||
except Exception as e:
|
||||
logger.warning(f" ⚠️ Could not drop table {name}: {e}")
|
||||
|
||||
# Execute migration within a transaction
|
||||
with self.engine.begin() as connection:
|
||||
op = OpMock(connection)
|
||||
# Configure Alembic context
|
||||
ctx = MigrationContext.configure(connection)
|
||||
op = Operations(ctx)
|
||||
|
||||
# Bind the alembic.op proxy to our operations object
|
||||
# This is necessary because migration files do 'from alembic import op'
|
||||
alembic.op._proxy = op
|
||||
|
||||
# Run the migration
|
||||
migration_module.upgrade()
|
||||
|
||||
# Record migration as applied
|
||||
connection.execute("""
|
||||
connection.execute(sa.text("""
|
||||
INSERT INTO _migrations (migration_name)
|
||||
VALUES (%s)
|
||||
VALUES (:name)
|
||||
ON CONFLICT DO NOTHING
|
||||
""", (migration_file.stem,))
|
||||
"""), {"name": migration_file.stem})
|
||||
|
||||
logger.info(f"✅ Applied migration: {migration_file.name}")
|
||||
return True
|
||||
|
||||
@ -26,6 +26,8 @@ def upgrade() -> None:
|
||||
sa.Column('specialty', sa.String(100), nullable=True),
|
||||
sa.Column('npi', sa.String(10), nullable=True),
|
||||
sa.Column('last_login_at', sa.DateTime(timezone=True), nullable=True),
|
||||
sa.Column('role', sa.String(50), server_default='user', nullable=False),
|
||||
sa.Column('is_active', sa.Boolean(), server_default='true', nullable=False),
|
||||
sa.Column('created_at', sa.DateTime(timezone=True), server_default=sa.text('CURRENT_TIMESTAMP'), nullable=False),
|
||||
sa.Column('updated_at', sa.DateTime(timezone=True), server_default=sa.text('CURRENT_TIMESTAMP'), onupdate=sa.text('CURRENT_TIMESTAMP'), nullable=False),
|
||||
)
|
||||
|
||||
@ -36,8 +36,6 @@ def upgrade() -> None:
|
||||
sa.Column('secondary_payer_id', postgresql.UUID(as_uuid=True), nullable=True),
|
||||
sa.Column('secondary_insurance_member_id', sa.String(100), nullable=True),
|
||||
sa.Column('emr_patient_id', sa.String(100), nullable=True),
|
||||
sa.Column('primary_payer_id', postgresql.UUID(as_uuid=True), sa.ForeignKey('.id'), nullable=False),
|
||||
sa.Column('secondary_payer_id', postgresql.UUID(as_uuid=True), sa.ForeignKey('.id'), nullable=False),
|
||||
sa.Column('created_at', sa.DateTime(timezone=True), server_default=sa.text('CURRENT_TIMESTAMP'), nullable=False),
|
||||
sa.Column('updated_at', sa.DateTime(timezone=True), server_default=sa.text('CURRENT_TIMESTAMP'), onupdate=sa.text('CURRENT_TIMESTAMP'), nullable=False),
|
||||
)
|
||||
|
||||
@ -30,11 +30,9 @@ def upgrade() -> None:
|
||||
sa.Column('encryption_key_id', sa.String(100), nullable=True),
|
||||
sa.Column('device_info', postgresql.JSONB(), nullable=True),
|
||||
sa.Column('noise_level', sa.String(255), nullable=True),
|
||||
sa.Column('status', sa.String(50), server_default='processing', nullable=False),
|
||||
sa.Column('template_id', postgresql.UUID(as_uuid=True), nullable=True),
|
||||
sa.Column('is_template_based', sa.Boolean(), nullable=False),
|
||||
sa.Column('user_id', postgresql.UUID(as_uuid=True), sa.ForeignKey('.id'), nullable=False),
|
||||
sa.Column('patient_id', postgresql.UUID(as_uuid=True), sa.ForeignKey('.id'), nullable=False),
|
||||
sa.Column('template_id', postgresql.UUID(as_uuid=True), sa.ForeignKey('.id'), nullable=False),
|
||||
sa.Column('created_at', sa.DateTime(timezone=True), server_default=sa.text('CURRENT_TIMESTAMP'), nullable=False),
|
||||
sa.Column('updated_at', sa.DateTime(timezone=True), server_default=sa.text('CURRENT_TIMESTAMP'), onupdate=sa.text('CURRENT_TIMESTAMP'), nullable=False),
|
||||
)
|
||||
|
||||
@ -27,11 +27,10 @@ def upgrade() -> None:
|
||||
sa.Column('low_confidence_segments', postgresql.JSONB(), nullable=True),
|
||||
sa.Column('processing_time_seconds', sa.Integer(), nullable=True),
|
||||
sa.Column('model_version', sa.String(50), nullable=False),
|
||||
sa.Column('status', sa.String(50), server_default='pending', nullable=False),
|
||||
sa.Column('is_manually_corrected', sa.Boolean(), nullable=False),
|
||||
sa.Column('corrected_by_user_id', postgresql.UUID(as_uuid=True), nullable=True),
|
||||
sa.Column('corrected_at', sa.DateTime(timezone=True), nullable=True),
|
||||
sa.Column('audio_recording_id', postgresql.UUID(as_uuid=True), sa.ForeignKey('.id'), nullable=False),
|
||||
sa.Column('corrected_by_user_id', postgresql.UUID(as_uuid=True), sa.ForeignKey('.id'), nullable=False),
|
||||
sa.Column('created_at', sa.DateTime(timezone=True), server_default=sa.text('CURRENT_TIMESTAMP'), nullable=False),
|
||||
sa.Column('updated_at', sa.DateTime(timezone=True), server_default=sa.text('CURRENT_TIMESTAMP'), onupdate=sa.text('CURRENT_TIMESTAMP'), nullable=False),
|
||||
)
|
||||
|
||||
@ -32,8 +32,6 @@ def upgrade() -> None:
|
||||
sa.Column('is_verified', sa.Boolean(), nullable=False),
|
||||
sa.Column('verified_by_user_id', postgresql.UUID(as_uuid=True), nullable=True),
|
||||
sa.Column('verified_at', sa.DateTime(timezone=True), nullable=True),
|
||||
sa.Column('transcript_id', postgresql.UUID(as_uuid=True), sa.ForeignKey('.id'), nullable=False),
|
||||
sa.Column('verified_by_user_id', postgresql.UUID(as_uuid=True), sa.ForeignKey('.id'), nullable=False),
|
||||
sa.Column('created_at', sa.DateTime(timezone=True), server_default=sa.text('CURRENT_TIMESTAMP'), nullable=False),
|
||||
sa.Column('updated_at', sa.DateTime(timezone=True), server_default=sa.text('CURRENT_TIMESTAMP'), onupdate=sa.text('CURRENT_TIMESTAMP'), nullable=False),
|
||||
)
|
||||
|
||||
@ -25,6 +25,8 @@ def upgrade() -> None:
|
||||
sa.Column('effective_date', sa.Date(), nullable=True),
|
||||
sa.Column('termination_date', sa.Date(), nullable=True),
|
||||
sa.Column('version', sa.String(20), nullable=False),
|
||||
sa.Column('is_billable', sa.Boolean(), server_default='true', nullable=False),
|
||||
sa.Column('is_active', sa.Boolean(), server_default='true', nullable=False),
|
||||
sa.Column('synonyms', postgresql.JSONB(), nullable=True),
|
||||
sa.Column('created_at', sa.DateTime(timezone=True), server_default=sa.text('CURRENT_TIMESTAMP'), nullable=False),
|
||||
sa.Column('updated_at', sa.DateTime(timezone=True), server_default=sa.text('CURRENT_TIMESTAMP'), onupdate=sa.text('CURRENT_TIMESTAMP'), nullable=False),
|
||||
|
||||
@ -30,6 +30,7 @@ def upgrade() -> None:
|
||||
sa.Column('rvu_facility', sa.Numeric(10, 2), nullable=True),
|
||||
sa.Column('rvu_non_facility', sa.Numeric(10, 2), nullable=True),
|
||||
sa.Column('global_period', sa.String(10), nullable=True),
|
||||
sa.Column('is_active', sa.Boolean(), server_default='true', nullable=False),
|
||||
sa.Column('synonyms', postgresql.JSONB(), nullable=True),
|
||||
sa.Column('created_at', sa.DateTime(timezone=True), server_default=sa.text('CURRENT_TIMESTAMP'), nullable=False),
|
||||
sa.Column('updated_at', sa.DateTime(timezone=True), server_default=sa.text('CURRENT_TIMESTAMP'), onupdate=sa.text('CURRENT_TIMESTAMP'), nullable=False),
|
||||
|
||||
@ -26,6 +26,7 @@ def upgrade() -> None:
|
||||
sa.Column('termination_date', sa.Date(), nullable=True),
|
||||
sa.Column('reimbursement_impact', sa.Numeric(10, 2), nullable=True),
|
||||
sa.Column('usage_rules', sa.Text(), nullable=True),
|
||||
sa.Column('is_active', sa.Boolean(), server_default='true', nullable=False),
|
||||
sa.Column('created_at', sa.DateTime(timezone=True), server_default=sa.text('CURRENT_TIMESTAMP'), nullable=False),
|
||||
sa.Column('updated_at', sa.DateTime(timezone=True), server_default=sa.text('CURRENT_TIMESTAMP'), onupdate=sa.text('CURRENT_TIMESTAMP'), nullable=False),
|
||||
)
|
||||
|
||||
@ -31,6 +31,7 @@ def upgrade() -> None:
|
||||
sa.Column('email', sa.String(255), nullable=True),
|
||||
sa.Column('website', sa.String(255), nullable=True),
|
||||
sa.Column('priority_rank', sa.Integer(), nullable=True),
|
||||
sa.Column('is_active', sa.Boolean(), server_default='true', nullable=False),
|
||||
sa.Column('notes', sa.Text(), nullable=True),
|
||||
sa.Column('created_at', sa.DateTime(timezone=True), server_default=sa.text('CURRENT_TIMESTAMP'), nullable=False),
|
||||
sa.Column('updated_at', sa.DateTime(timezone=True), server_default=sa.text('CURRENT_TIMESTAMP'), onupdate=sa.text('CURRENT_TIMESTAMP'), nullable=False),
|
||||
|
||||
@ -31,9 +31,8 @@ def upgrade() -> None:
|
||||
sa.Column('updated_by_user_id', postgresql.UUID(as_uuid=True), nullable=True),
|
||||
sa.Column('denial_count', sa.Integer(), nullable=False),
|
||||
sa.Column('last_denial_date', sa.DateTime(timezone=True), nullable=True),
|
||||
sa.Column('payer_id', postgresql.UUID(as_uuid=True), sa.ForeignKey('.id'), nullable=False),
|
||||
sa.Column('created_by_user_id', postgresql.UUID(as_uuid=True), sa.ForeignKey('.id'), nullable=False),
|
||||
sa.Column('updated_by_user_id', postgresql.UUID(as_uuid=True), sa.ForeignKey('.id'), nullable=False),
|
||||
sa.Column('is_active', sa.Boolean(), server_default='true', nullable=False),
|
||||
sa.Column('severity', sa.String(50), server_default='medium', nullable=False),
|
||||
sa.Column('created_at', sa.DateTime(timezone=True), server_default=sa.text('CURRENT_TIMESTAMP'), nullable=False),
|
||||
sa.Column('updated_at', sa.DateTime(timezone=True), server_default=sa.text('CURRENT_TIMESTAMP'), onupdate=sa.text('CURRENT_TIMESTAMP'), nullable=False),
|
||||
)
|
||||
|
||||
@ -25,6 +25,7 @@ def upgrade() -> None:
|
||||
sa.Column('effective_date', sa.Date(), nullable=False),
|
||||
sa.Column('deletion_date', sa.Date(), nullable=True),
|
||||
sa.Column('edit_rationale', sa.Text(), nullable=True),
|
||||
sa.Column('is_active', sa.Boolean(), server_default='true', nullable=False),
|
||||
sa.Column('created_at', sa.DateTime(timezone=True), server_default=sa.text('CURRENT_TIMESTAMP'), nullable=False),
|
||||
sa.Column('updated_at', sa.DateTime(timezone=True), server_default=sa.text('CURRENT_TIMESTAMP'), onupdate=sa.text('CURRENT_TIMESTAMP'), nullable=False),
|
||||
)
|
||||
|
||||
@ -31,6 +31,7 @@ def upgrade() -> None:
|
||||
sa.Column('termination_date', sa.Date(), nullable=True),
|
||||
sa.Column('last_review_date', sa.Date(), nullable=True),
|
||||
sa.Column('document_url', sa.String(500), nullable=True),
|
||||
sa.Column('is_active', sa.Boolean(), server_default='true', nullable=False),
|
||||
sa.Column('created_at', sa.DateTime(timezone=True), server_default=sa.text('CURRENT_TIMESTAMP'), nullable=False),
|
||||
sa.Column('updated_at', sa.DateTime(timezone=True), server_default=sa.text('CURRENT_TIMESTAMP'), onupdate=sa.text('CURRENT_TIMESTAMP'), nullable=False),
|
||||
)
|
||||
|
||||
@ -28,6 +28,7 @@ def upgrade() -> None:
|
||||
sa.Column('termination_date', sa.Date(), nullable=True),
|
||||
sa.Column('last_review_date', sa.Date(), nullable=True),
|
||||
sa.Column('document_url', sa.String(500), nullable=True),
|
||||
sa.Column('is_active', sa.Boolean(), server_default='true', nullable=False),
|
||||
sa.Column('created_at', sa.DateTime(timezone=True), server_default=sa.text('CURRENT_TIMESTAMP'), nullable=False),
|
||||
sa.Column('updated_at', sa.DateTime(timezone=True), server_default=sa.text('CURRENT_TIMESTAMP'), onupdate=sa.text('CURRENT_TIMESTAMP'), nullable=False),
|
||||
)
|
||||
|
||||
@ -29,8 +29,8 @@ def upgrade() -> None:
|
||||
sa.Column('documentation_requirements', sa.Text(), nullable=True),
|
||||
sa.Column('mdm_level', sa.String(255), nullable=True),
|
||||
sa.Column('usage_count', sa.Integer(), nullable=False),
|
||||
sa.Column('is_active', sa.Boolean(), server_default='true', nullable=False),
|
||||
sa.Column('created_by_user_id', postgresql.UUID(as_uuid=True), nullable=True),
|
||||
sa.Column('created_by_user_id', postgresql.UUID(as_uuid=True), sa.ForeignKey('.id'), nullable=False),
|
||||
sa.Column('created_at', sa.DateTime(timezone=True), server_default=sa.text('CURRENT_TIMESTAMP'), nullable=False),
|
||||
sa.Column('updated_at', sa.DateTime(timezone=True), server_default=sa.text('CURRENT_TIMESTAMP'), onupdate=sa.text('CURRENT_TIMESTAMP'), nullable=False),
|
||||
)
|
||||
|
||||
@ -38,6 +38,8 @@ def upgrade() -> None:
|
||||
sa.Column('scrubbing_failures', postgresql.JSONB(), nullable=True),
|
||||
sa.Column('corrective_actions', postgresql.JSONB(), nullable=True),
|
||||
sa.Column('confidence_score', sa.Numeric(10, 2), nullable=True),
|
||||
sa.Column('status', sa.String(50), server_default='draft', nullable=False),
|
||||
sa.Column('scrubbing_status', sa.String(50), server_default='pending', nullable=False),
|
||||
sa.Column('is_template_based', sa.Boolean(), nullable=False),
|
||||
sa.Column('template_id', postgresql.UUID(as_uuid=True), nullable=True),
|
||||
sa.Column('reviewed_by_user_id', postgresql.UUID(as_uuid=True), nullable=True),
|
||||
@ -47,13 +49,6 @@ def upgrade() -> None:
|
||||
sa.Column('denial_reason', sa.Text(), nullable=True),
|
||||
sa.Column('denial_code', sa.String(50), nullable=True),
|
||||
sa.Column('notes', sa.Text(), nullable=True),
|
||||
sa.Column('patient_id', postgresql.UUID(as_uuid=True), sa.ForeignKey('.id'), nullable=False),
|
||||
sa.Column('audio_recording_id', postgresql.UUID(as_uuid=True), sa.ForeignKey('.id'), nullable=False),
|
||||
sa.Column('transcript_id', postgresql.UUID(as_uuid=True), sa.ForeignKey('.id'), nullable=False),
|
||||
sa.Column('payer_id', postgresql.UUID(as_uuid=True), sa.ForeignKey('.id'), nullable=False),
|
||||
sa.Column('created_by_user_id', postgresql.UUID(as_uuid=True), sa.ForeignKey('.id'), nullable=False),
|
||||
sa.Column('reviewed_by_user_id', postgresql.UUID(as_uuid=True), sa.ForeignKey('.id'), nullable=False),
|
||||
sa.Column('template_id', postgresql.UUID(as_uuid=True), sa.ForeignKey('.id'), nullable=False),
|
||||
sa.Column('created_at', sa.DateTime(timezone=True), server_default=sa.text('CURRENT_TIMESTAMP'), nullable=False),
|
||||
sa.Column('updated_at', sa.DateTime(timezone=True), server_default=sa.text('CURRENT_TIMESTAMP'), onupdate=sa.text('CURRENT_TIMESTAMP'), nullable=False),
|
||||
)
|
||||
|
||||
@ -35,9 +35,6 @@ def upgrade() -> None:
|
||||
sa.Column('escalated_to_id', postgresql.UUID(as_uuid=True), nullable=True),
|
||||
sa.Column('escalated_at', sa.DateTime(timezone=True), nullable=True),
|
||||
sa.Column('reviewed_at', sa.DateTime(timezone=True), nullable=True),
|
||||
sa.Column('claim_id', postgresql.UUID(as_uuid=True), sa.ForeignKey('.id'), nullable=False),
|
||||
sa.Column('reviewer_id', postgresql.UUID(as_uuid=True), sa.ForeignKey('.id'), nullable=False),
|
||||
sa.Column('escalated_to_id', postgresql.UUID(as_uuid=True), sa.ForeignKey('.id'), nullable=False),
|
||||
sa.Column('created_at', sa.DateTime(timezone=True), server_default=sa.text('CURRENT_TIMESTAMP'), nullable=False),
|
||||
sa.Column('updated_at', sa.DateTime(timezone=True), server_default=sa.text('CURRENT_TIMESTAMP'), onupdate=sa.text('CURRENT_TIMESTAMP'), nullable=False),
|
||||
)
|
||||
|
||||
@ -35,7 +35,6 @@ def upgrade() -> None:
|
||||
sa.Column('metadata', postgresql.JSONB(), nullable=True),
|
||||
sa.Column('phi_accessed', sa.Boolean(), nullable=True),
|
||||
sa.Column('compliance_flag', sa.Boolean(), nullable=True),
|
||||
sa.Column('user_id', postgresql.UUID(as_uuid=True), sa.ForeignKey('.id'), nullable=False),
|
||||
sa.Column('created_at', sa.DateTime(timezone=True), server_default=sa.text('CURRENT_TIMESTAMP'), nullable=False),
|
||||
sa.Column('updated_at', sa.DateTime(timezone=True), server_default=sa.text('CURRENT_TIMESTAMP'), onupdate=sa.text('CURRENT_TIMESTAMP'), nullable=False),
|
||||
)
|
||||
|
||||
@ -36,7 +36,7 @@ def upgrade() -> None:
|
||||
sa.Column('preventive_actions', postgresql.JSONB(), nullable=True),
|
||||
sa.Column('related_lcd_ncd', postgresql.JSONB(), nullable=True),
|
||||
sa.Column('notes', sa.Text(), nullable=True),
|
||||
sa.Column('payer_id', postgresql.UUID(as_uuid=True), sa.ForeignKey('.id'), nullable=False),
|
||||
sa.Column('is_active', sa.Boolean(), server_default='true', nullable=False),
|
||||
sa.Column('created_at', sa.DateTime(timezone=True), server_default=sa.text('CURRENT_TIMESTAMP'), nullable=False),
|
||||
sa.Column('updated_at', sa.DateTime(timezone=True), server_default=sa.text('CURRENT_TIMESTAMP'), onupdate=sa.text('CURRENT_TIMESTAMP'), nullable=False),
|
||||
)
|
||||
|
||||
@ -42,9 +42,8 @@ def upgrade() -> None:
|
||||
sa.Column('rate_limit_per_minute', sa.Integer(), nullable=True),
|
||||
sa.Column('use_mock_data', sa.Boolean(), nullable=True),
|
||||
sa.Column('configuration_notes', sa.Text(), nullable=True),
|
||||
sa.Column('connection_status', sa.String(50), server_default='disconnected', nullable=False),
|
||||
sa.Column('created_by_id', postgresql.UUID(as_uuid=True), nullable=True),
|
||||
sa.Column('organization_id', postgresql.UUID(as_uuid=True), sa.ForeignKey('.id'), nullable=False),
|
||||
sa.Column('created_by_id', postgresql.UUID(as_uuid=True), sa.ForeignKey('.id'), nullable=False),
|
||||
sa.Column('created_at', sa.DateTime(timezone=True), server_default=sa.text('CURRENT_TIMESTAMP'), nullable=False),
|
||||
sa.Column('updated_at', sa.DateTime(timezone=True), server_default=sa.text('CURRENT_TIMESTAMP'), onupdate=sa.text('CURRENT_TIMESTAMP'), nullable=False),
|
||||
)
|
||||
|
||||
@ -39,10 +39,8 @@ def upgrade() -> None:
|
||||
sa.Column('last_used_at', sa.DateTime(timezone=True), nullable=True),
|
||||
sa.Column('metadata', postgresql.JSONB(), nullable=True),
|
||||
sa.Column('tags', postgresql.JSONB(), nullable=True),
|
||||
sa.Column('is_active', sa.Boolean(), server_default='true', nullable=False),
|
||||
sa.Column('uploaded_by_id', postgresql.UUID(as_uuid=True), nullable=True),
|
||||
sa.Column('payer_id', postgresql.UUID(as_uuid=True), sa.ForeignKey('.id'), nullable=False),
|
||||
sa.Column('parent_document_id', postgresql.UUID(as_uuid=True), sa.ForeignKey('.id'), nullable=False),
|
||||
sa.Column('uploaded_by_id', postgresql.UUID(as_uuid=True), sa.ForeignKey('.id'), nullable=False),
|
||||
sa.Column('created_at', sa.DateTime(timezone=True), server_default=sa.text('CURRENT_TIMESTAMP'), nullable=False),
|
||||
sa.Column('updated_at', sa.DateTime(timezone=True), server_default=sa.text('CURRENT_TIMESTAMP'), onupdate=sa.text('CURRENT_TIMESTAMP'), nullable=False),
|
||||
)
|
||||
|
||||
@ -35,7 +35,6 @@ def upgrade() -> None:
|
||||
sa.Column('corrected_value', sa.Text(), nullable=True),
|
||||
sa.Column('feedback_notes', sa.Text(), nullable=True),
|
||||
sa.Column('processing_time_ms', sa.Integer(), nullable=True),
|
||||
sa.Column('claim_id', postgresql.UUID(as_uuid=True), sa.ForeignKey('.id'), nullable=False),
|
||||
sa.Column('created_at', sa.DateTime(timezone=True), server_default=sa.text('CURRENT_TIMESTAMP'), nullable=False),
|
||||
sa.Column('updated_at', sa.DateTime(timezone=True), server_default=sa.text('CURRENT_TIMESTAMP'), onupdate=sa.text('CURRENT_TIMESTAMP'), nullable=False),
|
||||
)
|
||||
|
||||
@ -43,7 +43,7 @@ def upgrade() -> None:
|
||||
sa.Column('auto_fix_details', postgresql.JSONB(), nullable=True),
|
||||
sa.Column('requires_manual_review', sa.Boolean(), nullable=True),
|
||||
sa.Column('review_priority', sa.String(20), nullable=True),
|
||||
sa.Column('claim_id', postgresql.UUID(as_uuid=True), sa.ForeignKey('.id'), nullable=False),
|
||||
sa.Column('scrubbed_at', sa.DateTime(timezone=True), server_default=sa.text('CURRENT_TIMESTAMP'), nullable=False),
|
||||
sa.Column('created_at', sa.DateTime(timezone=True), server_default=sa.text('CURRENT_TIMESTAMP'), nullable=False),
|
||||
sa.Column('updated_at', sa.DateTime(timezone=True), server_default=sa.text('CURRENT_TIMESTAMP'), onupdate=sa.text('CURRENT_TIMESTAMP'), nullable=False),
|
||||
)
|
||||
|
||||
21
src/migrations/024_add_is_active_to_patients.py
Normal file
21
src/migrations/024_add_is_active_to_patients.py
Normal file
@ -0,0 +1,21 @@
|
||||
"""Migration to add is_active to patients
|
||||
|
||||
Revision ID: auto24
|
||||
Revises: auto23
|
||||
Create Date: auto
|
||||
"""
|
||||
from alembic import op
|
||||
import sqlalchemy as sa
|
||||
|
||||
# revision identifiers, used by Alembic.
|
||||
revision = 'auto24'
|
||||
down_revision = None
|
||||
branch_labels = None
|
||||
depends_on = None
|
||||
|
||||
def upgrade() -> None:
|
||||
# Adding `is_active` column to `patients`
|
||||
op.add_column('patients', sa.Column('is_active', sa.Boolean(), server_default='true', nullable=True))
|
||||
|
||||
def downgrade() -> None:
|
||||
op.drop_column('patients', 'is_active')
|
||||
53
src/models/__init__.py
Normal file
53
src/models/__init__.py
Normal file
@ -0,0 +1,53 @@
|
||||
from src.config.database import Base
|
||||
from sqlalchemy import BigInteger
|
||||
|
||||
# Import all models here to register them with Base.metadata
|
||||
from src.models.user_model import User
|
||||
from src.models.patient_model import Patient
|
||||
from src.models.payer_model import Payer
|
||||
from src.models.payer_rule_model import PayerRule
|
||||
from src.models.audio_recording_model import AudioRecording
|
||||
from src.models.transcript_model import Transcript
|
||||
from src.models.claim_model import Claim
|
||||
from src.models.claim_review_model import ClaimReview
|
||||
from src.models.claim_scrub_result_model import ClaimScrubResult
|
||||
from src.models.audit_log_model import AuditLog
|
||||
from src.models.clinical_entity_model import ClinicalEntity
|
||||
from src.models.confidence_score_model import ConfidenceScore
|
||||
from src.models.cpt_code_model import CPTCode
|
||||
from src.models.cpt_modifier_model import CPTModifier
|
||||
from src.models.denial_pattern_model import DenialPattern
|
||||
from src.models.emr_integration_model import EMRIntegration
|
||||
from src.models.icd10_code_model import ICD10Code
|
||||
from src.models.lcd_model import LCD
|
||||
from src.models.ncci_edit_model import NCCIEdit
|
||||
from src.models.ncd_model import NCD
|
||||
from src.models.procedure_template_model import ProcedureTemplate
|
||||
from src.models.rag_document_model import RAGDocument
|
||||
|
||||
# Export all models for easy importing elsewhere
|
||||
__all__ = [
|
||||
"Base",
|
||||
"User",
|
||||
"Patient",
|
||||
"Payer",
|
||||
"PayerRule",
|
||||
"AudioRecording",
|
||||
"Transcript",
|
||||
"Claim",
|
||||
"ClaimReview",
|
||||
"ClaimScrubResult",
|
||||
"AuditLog",
|
||||
"ClinicalEntity",
|
||||
"ConfidenceScore",
|
||||
"CPTCode",
|
||||
"CPTModifier",
|
||||
"DenialPattern",
|
||||
"EMRIntegration",
|
||||
"ICD10Code",
|
||||
"LCD",
|
||||
"NCCIEdit",
|
||||
"NCD",
|
||||
"ProcedureTemplate",
|
||||
"RAGDocument",
|
||||
]
|
||||
@ -1,4 +1,5 @@
|
||||
from sqlalchemy import Column, String, Integer, Boolean, DateTime, ForeignKey, Text, JSON, ARRAY, relationship
|
||||
from sqlalchemy import Column, String, Integer, Boolean, DateTime, ForeignKey, Text, JSON, ARRAY, BigInteger
|
||||
from sqlalchemy.orm import relationship
|
||||
from sqlalchemy.dialects.postgresql import UUID
|
||||
from src.config.database import Base
|
||||
from sqlalchemy.sql import func
|
||||
@ -8,8 +9,6 @@ class AudioRecording(Base):
|
||||
__tablename__ = 'audio_recordings'
|
||||
|
||||
id = Column(UUID(as_uuid=True), primary_key=True, default=uuid.uuid4, nullable=False)
|
||||
user_id = Column(UUID(as_uuid=True), nullable=False)
|
||||
patient_id = Column(UUID(as_uuid=True), nullable=False)
|
||||
encounter_id = Column(String(255), nullable=True)
|
||||
file_path = Column(String(255), nullable=False)
|
||||
file_name = Column(String(255), nullable=False)
|
||||
@ -20,19 +19,18 @@ class AudioRecording(Base):
|
||||
encryption_key_id = Column(String(255), nullable=True)
|
||||
device_info = Column(JSON, nullable=True)
|
||||
noise_level = Column(String(255), nullable=True)
|
||||
template_id = Column(UUID(as_uuid=True), nullable=True)
|
||||
is_template_based = Column(Boolean, nullable=False)
|
||||
|
||||
user_id = Column(UUID(as_uuid=True), ForeignKey('users.id'), nullable=False)
|
||||
user = relationship('User', back_populates='')
|
||||
patient_id = Column(UUID(as_uuid=True), ForeignKey('patients.id'), nullable=False)
|
||||
patient = relationship('Patient', back_populates='')
|
||||
template_id = Column(UUID(as_uuid=True), ForeignKey('procedure_templates.id'), nullable=True)
|
||||
procedureTemplate = relationship('ProcedureTemplate', back_populates='')
|
||||
|
||||
user = relationship('User', back_populates='audioRecordings')
|
||||
patient = relationship('Patient', back_populates='audioRecordings')
|
||||
procedureTemplate = relationship('ProcedureTemplate')
|
||||
|
||||
created_at = Column(DateTime(timezone=True), server_default=func.now(), nullable=False)
|
||||
updated_at = Column(DateTime(timezone=True), server_default=func.now(), onupdate=func.now(), nullable=False)
|
||||
|
||||
def __repr__(self):
|
||||
return f'<AudioRecording(id={self.id})>'
|
||||
|
||||
|
||||
@ -1,4 +1,5 @@
|
||||
from sqlalchemy import Column, String, Integer, Boolean, DateTime, ForeignKey, Text, JSON, ARRAY, relationship
|
||||
from sqlalchemy import Column, String, Integer, Boolean, DateTime, ForeignKey, Text, JSON, ARRAY
|
||||
from sqlalchemy.orm import relationship
|
||||
from sqlalchemy.dialects.postgresql import UUID
|
||||
from src.config.database import Base
|
||||
from sqlalchemy.sql import func
|
||||
@ -8,7 +9,6 @@ class AuditLog(Base):
|
||||
__tablename__ = 'audit_logs'
|
||||
|
||||
id = Column(UUID(as_uuid=True), primary_key=True, default=uuid.uuid4, nullable=False)
|
||||
user_id = Column(UUID(as_uuid=True), nullable=True)
|
||||
entity_type = Column(String(255), nullable=False)
|
||||
entity_id = Column(UUID(as_uuid=True), nullable=True)
|
||||
action = Column(String(255), nullable=False)
|
||||
@ -22,16 +22,15 @@ class AuditLog(Base):
|
||||
request_id = Column(String(255), nullable=True)
|
||||
status = Column(String(255), nullable=False)
|
||||
error_message = Column(Text, nullable=True)
|
||||
metadata = Column(JSON, nullable=True)
|
||||
doc_metadata = Column(JSON, nullable=True)
|
||||
phi_accessed = Column(Boolean, nullable=True)
|
||||
compliance_flag = Column(Boolean, nullable=True)
|
||||
|
||||
user_id = Column(UUID(as_uuid=True), ForeignKey('users.id'), nullable=True)
|
||||
user = relationship('User', back_populates='')
|
||||
user = relationship('User', back_populates='auditLogs')
|
||||
|
||||
created_at = Column(DateTime(timezone=True), server_default=func.now(), nullable=False)
|
||||
updated_at = Column(DateTime(timezone=True), server_default=func.now(), onupdate=func.now(), nullable=False)
|
||||
|
||||
def __repr__(self):
|
||||
return f'<AuditLog(id={self.id})>'
|
||||
|
||||
|
||||
@ -1,4 +1,5 @@
|
||||
from sqlalchemy import Column, String, Integer, Boolean, DateTime, ForeignKey, Text, JSON, ARRAY, relationship
|
||||
from sqlalchemy import Column, String, Integer, Boolean, DateTime, ForeignKey, Text, JSON, ARRAY
|
||||
from sqlalchemy.orm import relationship
|
||||
from sqlalchemy.dialects.postgresql import UUID
|
||||
from src.config.database import Base
|
||||
from sqlalchemy.sql import func
|
||||
@ -9,13 +10,8 @@ class Claim(Base):
|
||||
|
||||
id = Column(UUID(as_uuid=True), primary_key=True, default=uuid.uuid4, nullable=False)
|
||||
claim_number = Column(String(255), nullable=False, unique=True)
|
||||
patient_id = Column(UUID(as_uuid=True), nullable=False)
|
||||
audio_recording_id = Column(UUID(as_uuid=True), nullable=True)
|
||||
transcript_id = Column(UUID(as_uuid=True), nullable=True)
|
||||
payer_id = Column(UUID(as_uuid=True), nullable=False)
|
||||
encounter_id = Column(String(255), nullable=True)
|
||||
service_date = Column(DateTime, nullable=False)
|
||||
created_by_user_id = Column(UUID(as_uuid=True), nullable=False)
|
||||
diagnosis_codes = Column(JSON, nullable=False)
|
||||
procedure_codes = Column(JSON, nullable=False)
|
||||
modifiers = Column(JSON, nullable=True)
|
||||
@ -29,8 +25,6 @@ class Claim(Base):
|
||||
corrective_actions = Column(JSON, nullable=True)
|
||||
confidence_score = Column(String(255), nullable=True)
|
||||
is_template_based = Column(Boolean, nullable=False)
|
||||
template_id = Column(UUID(as_uuid=True), nullable=True)
|
||||
reviewed_by_user_id = Column(UUID(as_uuid=True), nullable=True)
|
||||
reviewed_at = Column(DateTime, nullable=True)
|
||||
submitted_at = Column(DateTime, nullable=True)
|
||||
paid_at = Column(DateTime, nullable=True)
|
||||
@ -39,23 +33,23 @@ class Claim(Base):
|
||||
notes = Column(Text, nullable=True)
|
||||
|
||||
patient_id = Column(UUID(as_uuid=True), ForeignKey('patients.id'), nullable=False)
|
||||
patient = relationship('Patient', back_populates='')
|
||||
audio_recording_id = Column(UUID(as_uuid=True), ForeignKey('audio_recordings.id'), nullable=True)
|
||||
audioRecording = relationship('AudioRecording', back_populates='')
|
||||
transcript_id = Column(UUID(as_uuid=True), ForeignKey('transcripts.id'), nullable=True)
|
||||
transcript = relationship('Transcript', back_populates='')
|
||||
payer_id = Column(UUID(as_uuid=True), ForeignKey('payers.id'), nullable=False)
|
||||
payer = relationship('Payer', back_populates='')
|
||||
created_by_user_id = Column(UUID(as_uuid=True), ForeignKey('users.id'), nullable=False)
|
||||
user = relationship('User', back_populates='')
|
||||
reviewed_by_user_id = Column(UUID(as_uuid=True), ForeignKey('users.id'), nullable=True)
|
||||
user = relationship('User', back_populates='')
|
||||
template_id = Column(UUID(as_uuid=True), ForeignKey('procedure_templates.id'), nullable=True)
|
||||
procedureTemplate = relationship('ProcedureTemplate', back_populates='')
|
||||
|
||||
patient = relationship('Patient', back_populates='claims')
|
||||
audioRecording = relationship('AudioRecording')
|
||||
transcript = relationship('Transcript')
|
||||
payer = relationship('Payer')
|
||||
creator = relationship('User', foreign_keys=[created_by_user_id], back_populates='claims')
|
||||
reviewer = relationship('User', foreign_keys=[reviewed_by_user_id], back_populates='reviewedClaims')
|
||||
procedureTemplate = relationship('ProcedureTemplate')
|
||||
|
||||
created_at = Column(DateTime(timezone=True), server_default=func.now(), nullable=False)
|
||||
updated_at = Column(DateTime(timezone=True), server_default=func.now(), onupdate=func.now(), nullable=False)
|
||||
|
||||
def __repr__(self):
|
||||
return f'<Claim(id={self.id})>'
|
||||
|
||||
|
||||
@ -1,4 +1,5 @@
|
||||
from sqlalchemy import Column, String, Integer, Boolean, DateTime, ForeignKey, Text, JSON, ARRAY, relationship
|
||||
from sqlalchemy import Column, String, Integer, Boolean, DateTime, ForeignKey, Text, JSON, ARRAY
|
||||
from sqlalchemy.orm import relationship
|
||||
from sqlalchemy.dialects.postgresql import UUID
|
||||
from src.config.database import Base
|
||||
from sqlalchemy.sql import func
|
||||
@ -8,8 +9,8 @@ class ClaimReview(Base):
|
||||
__tablename__ = 'claim_reviews'
|
||||
|
||||
id = Column(UUID(as_uuid=True), primary_key=True, default=uuid.uuid4, nullable=False)
|
||||
claim_id = Column(UUID(as_uuid=True), nullable=False)
|
||||
reviewer_id = Column(UUID(as_uuid=True), nullable=False)
|
||||
claim_id = Column(UUID(as_uuid=True), ForeignKey('claims.id'), nullable=False)
|
||||
reviewer_id = Column(UUID(as_uuid=True), ForeignKey('users.id'), nullable=False)
|
||||
review_status = Column(String(255), nullable=False)
|
||||
review_type = Column(String(255), nullable=False)
|
||||
confidence_threshold_triggered = Column(Boolean, nullable=True)
|
||||
@ -22,16 +23,12 @@ class ClaimReview(Base):
|
||||
corrective_actions = Column(JSON, nullable=True)
|
||||
review_duration_seconds = Column(Integer, nullable=True)
|
||||
escalation_reason = Column(Text, nullable=True)
|
||||
escalated_to_id = Column(UUID(as_uuid=True), nullable=True)
|
||||
escalated_to_id = Column(UUID(as_uuid=True), ForeignKey('users.id'), nullable=True)
|
||||
escalated_at = Column(DateTime, nullable=True)
|
||||
reviewed_at = Column(DateTime, nullable=True)
|
||||
|
||||
claim_id = Column(UUID(as_uuid=True), ForeignKey('claims.id'), nullable=False)
|
||||
claim = relationship('Claim', back_populates='')
|
||||
reviewer_id = Column(UUID(as_uuid=True), ForeignKey('users.id'), nullable=False)
|
||||
user = relationship('User', back_populates='')
|
||||
escalated_to_id = Column(UUID(as_uuid=True), ForeignKey('users.id'), nullable=True)
|
||||
user = relationship('User', back_populates='')
|
||||
claim = relationship('Claim', foreign_keys=[claim_id])
|
||||
reviewer = relationship('User', foreign_keys=[reviewer_id])
|
||||
escalated_to = relationship('User', foreign_keys=[escalated_to_id])
|
||||
|
||||
created_at = Column(DateTime(timezone=True), server_default=func.now(), nullable=False)
|
||||
updated_at = Column(DateTime(timezone=True), server_default=func.now(), onupdate=func.now(), nullable=False)
|
||||
|
||||
@ -1,4 +1,5 @@
|
||||
from sqlalchemy import Column, String, Integer, Boolean, DateTime, ForeignKey, Text, JSON, ARRAY, relationship
|
||||
from sqlalchemy import Column, String, Integer, Boolean, DateTime, ForeignKey, Text, JSON, ARRAY
|
||||
from sqlalchemy.orm import relationship
|
||||
from sqlalchemy.dialects.postgresql import UUID
|
||||
from src.config.database import Base
|
||||
from sqlalchemy.sql import func
|
||||
|
||||
@ -1,4 +1,5 @@
|
||||
from sqlalchemy import Column, String, Integer, Boolean, DateTime, ForeignKey, Text, JSON, ARRAY, relationship
|
||||
from sqlalchemy import Column, String, Integer, Boolean, DateTime, ForeignKey, Text, JSON, ARRAY
|
||||
from sqlalchemy.orm import relationship
|
||||
from sqlalchemy.dialects.postgresql import UUID
|
||||
from src.config.database import Base
|
||||
from sqlalchemy.sql import func
|
||||
@ -8,7 +9,6 @@ class ClinicalEntity(Base):
|
||||
__tablename__ = 'clinical_entities'
|
||||
|
||||
id = Column(UUID(as_uuid=True), primary_key=True, default=uuid.uuid4, nullable=False)
|
||||
transcript_id = Column(UUID(as_uuid=True), nullable=False)
|
||||
entity_type = Column(String(255), nullable=False)
|
||||
entity_text = Column(String(255), nullable=False)
|
||||
normalized_text = Column(String(255), nullable=True)
|
||||
@ -16,21 +16,21 @@ class ClinicalEntity(Base):
|
||||
start_position = Column(Integer, nullable=True)
|
||||
end_position = Column(Integer, nullable=True)
|
||||
context = Column(Text, nullable=True)
|
||||
metadata = Column(JSON, nullable=True)
|
||||
doc_metadata = Column(JSON, nullable=True)
|
||||
is_negated = Column(Boolean, nullable=False)
|
||||
is_historical = Column(Boolean, nullable=False)
|
||||
is_verified = Column(Boolean, nullable=False)
|
||||
verified_by_user_id = Column(UUID(as_uuid=True), nullable=True)
|
||||
verified_at = Column(DateTime, nullable=True)
|
||||
|
||||
transcript_id = Column(UUID(as_uuid=True), ForeignKey('transcripts.id'), nullable=False)
|
||||
transcript = relationship('Transcript', back_populates='')
|
||||
verified_by_user_id = Column(UUID(as_uuid=True), ForeignKey('users.id'), nullable=True)
|
||||
user = relationship('User', back_populates='')
|
||||
|
||||
transcript = relationship('Transcript', back_populates='clinicalEntitys')
|
||||
verifier = relationship('User', back_populates='verifiedClinicalEntities')
|
||||
|
||||
|
||||
created_at = Column(DateTime(timezone=True), server_default=func.now(), nullable=False)
|
||||
updated_at = Column(DateTime(timezone=True), server_default=func.now(), onupdate=func.now(), nullable=False)
|
||||
|
||||
def __repr__(self):
|
||||
return f'<ClinicalEntity(id={self.id})>'
|
||||
|
||||
|
||||
@ -1,4 +1,5 @@
|
||||
from sqlalchemy import Column, String, Integer, Boolean, DateTime, ForeignKey, Text, JSON, ARRAY, relationship
|
||||
from sqlalchemy import Column, String, Integer, Boolean, DateTime, ForeignKey, Text, JSON, ARRAY
|
||||
from sqlalchemy.orm import relationship
|
||||
from sqlalchemy.dialects.postgresql import UUID
|
||||
from src.config.database import Base
|
||||
from sqlalchemy.sql import func
|
||||
|
||||
@ -1,4 +1,5 @@
|
||||
from sqlalchemy import Column, String, Integer, Boolean, DateTime, ForeignKey, Text, JSON, ARRAY, relationship
|
||||
from sqlalchemy import Column, String, Integer, Boolean, DateTime, ForeignKey, Text, JSON, ARRAY
|
||||
from sqlalchemy.orm import relationship
|
||||
from sqlalchemy.dialects.postgresql import UUID
|
||||
from src.config.database import Base
|
||||
from sqlalchemy.sql import func
|
||||
@ -8,7 +9,6 @@ class DenialPattern(Base):
|
||||
__tablename__ = 'denial_patterns'
|
||||
|
||||
id = Column(UUID(as_uuid=True), primary_key=True, default=uuid.uuid4, nullable=False)
|
||||
payer_id = Column(UUID(as_uuid=True), nullable=False)
|
||||
payer_name = Column(String(255), nullable=False)
|
||||
denial_code = Column(String(255), nullable=False)
|
||||
denial_reason = Column(Text, nullable=False)
|
||||
@ -26,9 +26,11 @@ class DenialPattern(Base):
|
||||
preventive_actions = Column(JSON, nullable=True)
|
||||
related_lcd_ncd = Column(JSON, nullable=True)
|
||||
notes = Column(Text, nullable=True)
|
||||
|
||||
|
||||
payer_id = Column(UUID(as_uuid=True), ForeignKey('payers.id'), nullable=False)
|
||||
payer = relationship('Payer', back_populates='')
|
||||
payer = relationship('Payer', back_populates='denialPatterns')
|
||||
|
||||
|
||||
created_at = Column(DateTime(timezone=True), server_default=func.now(), nullable=False)
|
||||
updated_at = Column(DateTime(timezone=True), server_default=func.now(), onupdate=func.now(), nullable=False)
|
||||
|
||||
@ -1,4 +1,5 @@
|
||||
from sqlalchemy import Column, String, Integer, Boolean, DateTime, ForeignKey, Text, JSON, ARRAY, relationship
|
||||
from sqlalchemy import Column, String, Integer, Boolean, DateTime, ForeignKey, Text, JSON, ARRAY
|
||||
from sqlalchemy.orm import relationship
|
||||
from sqlalchemy.dialects.postgresql import UUID
|
||||
from src.config.database import Base
|
||||
from sqlalchemy.sql import func
|
||||
@ -32,12 +33,10 @@ class EMRIntegration(Base):
|
||||
rate_limit_per_minute = Column(Integer, nullable=True)
|
||||
use_mock_data = Column(Boolean, nullable=True)
|
||||
configuration_notes = Column(Text, nullable=True)
|
||||
created_by_id = Column(UUID(as_uuid=True), nullable=True)
|
||||
|
||||
organization_id = Column(UUID(as_uuid=True), ForeignKey('organizations.id'), nullable=False)
|
||||
organization = relationship('Organization', back_populates='')
|
||||
|
||||
created_by_id = Column(UUID(as_uuid=True), ForeignKey('users.id'), nullable=True)
|
||||
user = relationship('User', back_populates='')
|
||||
creator = relationship('User', back_populates='createdEMRIntegrations')
|
||||
|
||||
|
||||
created_at = Column(DateTime(timezone=True), server_default=func.now(), nullable=False)
|
||||
updated_at = Column(DateTime(timezone=True), server_default=func.now(), onupdate=func.now(), nullable=False)
|
||||
|
||||
@ -1,4 +1,5 @@
|
||||
from sqlalchemy import Column, String, Integer, Boolean, DateTime, ForeignKey, Text, JSON, ARRAY, relationship
|
||||
from sqlalchemy import Column, String, Integer, Boolean, DateTime, ForeignKey, Text, JSON, ARRAY
|
||||
from sqlalchemy.orm import relationship
|
||||
from sqlalchemy.dialects.postgresql import UUID
|
||||
from src.config.database import Base
|
||||
from sqlalchemy.sql import func
|
||||
@ -21,19 +22,19 @@ class Patient(Base):
|
||||
zip_code = Column(String(255), nullable=True)
|
||||
phone = Column(String(255), nullable=True)
|
||||
email = Column(String(255), nullable=True)
|
||||
primary_payer_id = Column(UUID(as_uuid=True), nullable=True)
|
||||
primary_insurance_member_id = Column(String(255), nullable=True)
|
||||
secondary_payer_id = Column(UUID(as_uuid=True), nullable=True)
|
||||
secondary_insurance_member_id = Column(String(255), nullable=True)
|
||||
emr_patient_id = Column(String(255), nullable=True)
|
||||
|
||||
primary_payer_id = Column(UUID(as_uuid=True), ForeignKey('payers.id'), nullable=True)
|
||||
payer = relationship('Payer', back_populates='')
|
||||
secondary_payer_id = Column(UUID(as_uuid=True), ForeignKey('payers.id'), nullable=True)
|
||||
payer = relationship('Payer', back_populates='')
|
||||
|
||||
primary_insurance_member_id = Column(String(255), nullable=True)
|
||||
secondary_insurance_member_id = Column(String(255), nullable=True)
|
||||
emr_patient_id = Column(String(255), nullable=True)
|
||||
is_active = Column(Boolean, default=True)
|
||||
|
||||
primary_payer = relationship('Payer', foreign_keys=[primary_payer_id], back_populates='primary_patients')
|
||||
secondary_payer = relationship('Payer', foreign_keys=[secondary_payer_id], back_populates='secondary_patients')
|
||||
|
||||
audioRecordings = relationship('AudioRecording', back_populates='patient')
|
||||
|
||||
claims = relationship('Claim', back_populates='patient')
|
||||
|
||||
created_at = Column(DateTime(timezone=True), server_default=func.now(), nullable=False)
|
||||
|
||||
@ -1,4 +1,5 @@
|
||||
from sqlalchemy import Column, String, Integer, Boolean, DateTime, ForeignKey, Text, JSON, ARRAY, relationship
|
||||
from sqlalchemy import Column, String, Integer, Boolean, DateTime, ForeignKey, Text, JSON, ARRAY
|
||||
from sqlalchemy.orm import relationship
|
||||
from sqlalchemy.dialects.postgresql import UUID
|
||||
from src.config.database import Base
|
||||
from sqlalchemy.sql import func
|
||||
@ -24,8 +25,13 @@ class Payer(Base):
|
||||
notes = Column(Text, nullable=True)
|
||||
|
||||
payerRules = relationship('PayerRule', back_populates='payer')
|
||||
ragDocuments = relationship('RAGDocument', back_populates='payer')
|
||||
denialPatterns = relationship('DenialPattern', back_populates='payer')
|
||||
|
||||
patients = relationship('Patient', back_populates='payer')
|
||||
|
||||
|
||||
primary_patients = relationship('Patient', foreign_keys='[Patient.primary_payer_id]', back_populates='primary_payer')
|
||||
secondary_patients = relationship('Patient', foreign_keys='[Patient.secondary_payer_id]', back_populates='secondary_payer')
|
||||
|
||||
created_at = Column(DateTime(timezone=True), server_default=func.now(), nullable=False)
|
||||
updated_at = Column(DateTime(timezone=True), server_default=func.now(), onupdate=func.now(), nullable=False)
|
||||
|
||||
@ -1,4 +1,5 @@
|
||||
from sqlalchemy import Column, String, Integer, Boolean, DateTime, ForeignKey, Text, JSON, ARRAY, relationship
|
||||
from sqlalchemy import Column, String, Integer, Boolean, DateTime, ForeignKey, Text, JSON, ARRAY
|
||||
from sqlalchemy.orm import relationship
|
||||
from sqlalchemy.dialects.postgresql import UUID
|
||||
from src.config.database import Base
|
||||
from sqlalchemy.sql import func
|
||||
@ -8,7 +9,6 @@ class PayerRule(Base):
|
||||
__tablename__ = 'payer_rules'
|
||||
|
||||
id = Column(UUID(as_uuid=True), primary_key=True, default=uuid.uuid4, nullable=False)
|
||||
payer_id = Column(UUID(as_uuid=True), nullable=False)
|
||||
rule_name = Column(String(255), nullable=False)
|
||||
rule_type = Column(String(255), nullable=False)
|
||||
rule_description = Column(Text, nullable=False)
|
||||
@ -17,17 +17,19 @@ class PayerRule(Base):
|
||||
affected_icd10_codes = Column(JSON, nullable=True)
|
||||
effective_date = Column(DateTime, nullable=False)
|
||||
termination_date = Column(DateTime, nullable=True)
|
||||
created_by_user_id = Column(UUID(as_uuid=True), nullable=True)
|
||||
updated_by_user_id = Column(UUID(as_uuid=True), nullable=True)
|
||||
denial_count = Column(Integer, nullable=False)
|
||||
last_denial_date = Column(DateTime, nullable=True)
|
||||
|
||||
payer_id = Column(UUID(as_uuid=True), ForeignKey('payers.id'), nullable=False)
|
||||
payer = relationship('Payer', back_populates='')
|
||||
payer = relationship('Payer', back_populates='payerRules')
|
||||
|
||||
created_by_user_id = Column(UUID(as_uuid=True), ForeignKey('users.id'), nullable=True)
|
||||
user = relationship('User', back_populates='')
|
||||
creator = relationship('User', foreign_keys=[created_by_user_id], back_populates='createdPayerRules')
|
||||
|
||||
updated_by_user_id = Column(UUID(as_uuid=True), ForeignKey('users.id'), nullable=True)
|
||||
user = relationship('User', back_populates='')
|
||||
updater = relationship('User', foreign_keys=[updated_by_user_id], back_populates='updatedPayerRules')
|
||||
|
||||
|
||||
|
||||
created_at = Column(DateTime(timezone=True), server_default=func.now(), nullable=False)
|
||||
updated_at = Column(DateTime(timezone=True), server_default=func.now(), onupdate=func.now(), nullable=False)
|
||||
|
||||
@ -1,4 +1,5 @@
|
||||
from sqlalchemy import Column, String, Integer, Boolean, DateTime, ForeignKey, Text, JSON, ARRAY, relationship
|
||||
from sqlalchemy import Column, String, Integer, Boolean, DateTime, ForeignKey, Text, JSON, ARRAY
|
||||
from sqlalchemy.orm import relationship
|
||||
from sqlalchemy.dialects.postgresql import UUID
|
||||
from src.config.database import Base
|
||||
from sqlalchemy.sql import func
|
||||
@ -19,10 +20,10 @@ class ProcedureTemplate(Base):
|
||||
documentation_requirements = Column(Text, nullable=True)
|
||||
mdm_level = Column(String(255), nullable=True)
|
||||
usage_count = Column(Integer, nullable=False)
|
||||
created_by_user_id = Column(UUID(as_uuid=True), nullable=True)
|
||||
|
||||
created_by_user_id = Column(UUID(as_uuid=True), ForeignKey('users.id'), nullable=True)
|
||||
user = relationship('User', back_populates='')
|
||||
creator = relationship('User', back_populates='createdProcedureTemplates')
|
||||
|
||||
|
||||
audioRecordings = relationship('AudioRecording', back_populates='procedureTemplate')
|
||||
|
||||
|
||||
@ -1,4 +1,5 @@
|
||||
from sqlalchemy import Column, String, Integer, Boolean, DateTime, ForeignKey, Text, JSON, ARRAY, relationship
|
||||
from sqlalchemy import Column, String, Integer, Boolean, DateTime, ForeignKey, Text, JSON, ARRAY
|
||||
from sqlalchemy.orm import relationship
|
||||
from sqlalchemy.dialects.postgresql import UUID
|
||||
from src.config.database import Base
|
||||
from sqlalchemy.sql import func
|
||||
@ -27,16 +28,19 @@ class RAGDocument(Base):
|
||||
relevance_score = Column(String(255), nullable=True)
|
||||
usage_count = Column(Integer, nullable=True)
|
||||
last_used_at = Column(DateTime, nullable=True)
|
||||
metadata = Column(JSON, nullable=True)
|
||||
doc_doc_doc_metadata = Column(JSON, nullable=True)
|
||||
tags = Column(JSON, nullable=True)
|
||||
uploaded_by_id = Column(UUID(as_uuid=True), nullable=True)
|
||||
|
||||
payer_id = Column(UUID(as_uuid=True), ForeignKey('payers.id'), nullable=True)
|
||||
payer = relationship('Payer', back_populates='')
|
||||
payer = relationship('Payer', back_populates='ragDocuments')
|
||||
|
||||
parent_document_id = Column(UUID(as_uuid=True), ForeignKey('rag_documents.id'), nullable=True)
|
||||
rAGDocument = relationship('RAGDocument', back_populates='')
|
||||
parent_document = relationship('RAGDocument', remote_side=[id], back_populates='chunks')
|
||||
chunks = relationship('RAGDocument', back_populates='parent_document')
|
||||
|
||||
uploaded_by_id = Column(UUID(as_uuid=True), ForeignKey('users.id'), nullable=True)
|
||||
user = relationship('User', back_populates='')
|
||||
uploader = relationship('User', back_populates='uploadedDocuments')
|
||||
|
||||
|
||||
created_at = Column(DateTime(timezone=True), server_default=func.now(), nullable=False)
|
||||
updated_at = Column(DateTime(timezone=True), server_default=func.now(), onupdate=func.now(), nullable=False)
|
||||
|
||||
@ -1,4 +1,5 @@
|
||||
from sqlalchemy import Column, String, Integer, Boolean, DateTime, ForeignKey, Text, JSON, ARRAY, relationship
|
||||
from sqlalchemy import Column, String, Integer, Boolean, DateTime, ForeignKey, Text, JSON, ARRAY
|
||||
from sqlalchemy.orm import relationship
|
||||
from sqlalchemy.dialects.postgresql import UUID
|
||||
from src.config.database import Base
|
||||
from sqlalchemy.sql import func
|
||||
@ -8,7 +9,6 @@ class Transcript(Base):
|
||||
__tablename__ = 'transcripts'
|
||||
|
||||
id = Column(UUID(as_uuid=True), primary_key=True, default=uuid.uuid4, nullable=False)
|
||||
audio_recording_id = Column(UUID(as_uuid=True), nullable=False, unique=True)
|
||||
raw_text = Column(Text, nullable=False)
|
||||
corrected_text = Column(Text, nullable=True)
|
||||
word_error_rate = Column(String(255), nullable=True)
|
||||
@ -18,14 +18,13 @@ class Transcript(Base):
|
||||
processing_time_seconds = Column(Integer, nullable=True)
|
||||
model_version = Column(String(255), nullable=False)
|
||||
is_manually_corrected = Column(Boolean, nullable=False)
|
||||
corrected_by_user_id = Column(UUID(as_uuid=True), nullable=True)
|
||||
corrected_at = Column(DateTime, nullable=True)
|
||||
|
||||
audio_recording_id = Column(UUID(as_uuid=True), ForeignKey('audio_recordings.id'), nullable=False)
|
||||
audioRecording = relationship('AudioRecording', back_populates='')
|
||||
audio_recording_id = Column(UUID(as_uuid=True), ForeignKey('audio_recordings.id'), nullable=False, unique=True)
|
||||
corrected_by_user_id = Column(UUID(as_uuid=True), ForeignKey('users.id'), nullable=True)
|
||||
user = relationship('User', back_populates='')
|
||||
|
||||
|
||||
audioRecording = relationship('AudioRecording')
|
||||
user = relationship('User')
|
||||
clinicalEntitys = relationship('ClinicalEntity', back_populates='transcript')
|
||||
|
||||
created_at = Column(DateTime(timezone=True), server_default=func.now(), nullable=False)
|
||||
@ -33,4 +32,3 @@ class Transcript(Base):
|
||||
|
||||
def __repr__(self):
|
||||
return f'<Transcript(id={self.id})>'
|
||||
|
||||
|
||||
@ -1,4 +1,5 @@
|
||||
from sqlalchemy import Column, String, Integer, Boolean, DateTime, ForeignKey, Text, JSON, ARRAY, relationship
|
||||
from sqlalchemy import Column, String, Integer, Boolean, DateTime, ForeignKey, Text, JSON, ARRAY
|
||||
from sqlalchemy.orm import relationship
|
||||
from sqlalchemy.dialects.postgresql import UUID
|
||||
from src.config.database import Base
|
||||
from sqlalchemy.sql import func
|
||||
@ -16,10 +17,22 @@ class User(Base):
|
||||
specialty = Column(String(255), nullable=True)
|
||||
npi = Column(String(255), nullable=True)
|
||||
last_login_at = Column(DateTime, nullable=True)
|
||||
role = Column(String(50), default='user', nullable=False)
|
||||
is_active = Column(Boolean, default=True, nullable=False)
|
||||
|
||||
audioRecordings = relationship('AudioRecording', back_populates='user')
|
||||
claims = relationship('Claim', foreign_keys='[Claim.created_by_user_id]', back_populates='creator')
|
||||
reviewedClaims = relationship('Claim', foreign_keys='[Claim.reviewed_by_user_id]', back_populates='reviewer')
|
||||
auditLogs = relationship('AuditLog', back_populates='user')
|
||||
createdPayerRules = relationship('PayerRule', foreign_keys='[PayerRule.created_by_user_id]', back_populates='creator')
|
||||
updatedPayerRules = relationship('PayerRule', foreign_keys='[PayerRule.updated_by_user_id]', back_populates='updater')
|
||||
uploadedDocuments = relationship('RAGDocument', back_populates='uploader')
|
||||
createdEMRIntegrations = relationship('EMRIntegration', back_populates='creator')
|
||||
createdProcedureTemplates = relationship('ProcedureTemplate', back_populates='creator')
|
||||
verifiedClinicalEntities = relationship('ClinicalEntity', back_populates='verifier')
|
||||
|
||||
|
||||
|
||||
claims = relationship('Claim', back_populates='user')
|
||||
|
||||
created_at = Column(DateTime(timezone=True), server_default=func.now(), nullable=False)
|
||||
updated_at = Column(DateTime(timezone=True), server_default=func.now(), onupdate=func.now(), nullable=False)
|
||||
|
||||
@ -12,7 +12,7 @@ from langchain_community.document_loaders import (
|
||||
UnstructuredExcelLoader
|
||||
)
|
||||
from langchain.text_splitter import RecursiveCharacterTextSplitter
|
||||
from langchain_community.vectorstores import Chroma
|
||||
# from langchain_community.vectorstores import Chroma
|
||||
from langchain_huggingface import HuggingFaceEmbeddings
|
||||
from langchain_openai import OpenAIEmbeddings
|
||||
from loguru import logger
|
||||
@ -75,11 +75,12 @@ class RAGIngestor:
|
||||
logger.info(f"Split document into {len(chunks)} chunks")
|
||||
|
||||
# 3 & 4. Embedding & Storage
|
||||
vectorstore = Chroma.from_documents(
|
||||
documents=chunks,
|
||||
embedding=self.embeddings,
|
||||
persist_directory=self.persist_directory,
|
||||
collection_name=collection_name
|
||||
)
|
||||
# vectorstore = Chroma.from_documents(
|
||||
# documents=chunks,
|
||||
# embedding=self.embeddings,
|
||||
# persist_directory=self.persist_directory,
|
||||
# collection_name=collection_name
|
||||
# )
|
||||
logger.warning("Vector storage (Chroma) is temporarily disabled due to installation issues.")
|
||||
|
||||
return len(chunks)
|
||||
|
||||
@ -4,7 +4,7 @@ Handles query embedding, vector retrieval, reranking, and LLM generation.
|
||||
"""
|
||||
import time
|
||||
from typing import List, Dict, Any, Optional
|
||||
from langchain_community.vectorstores import Chroma
|
||||
# from langchain_community.vectorstores import Chroma
|
||||
from langchain_huggingface import HuggingFaceEmbeddings
|
||||
from langchain_openai import OpenAIEmbeddings, ChatOpenAI
|
||||
from langchain_anthropic import ChatAnthropic
|
||||
@ -54,11 +54,13 @@ Helpful Answer:"""
|
||||
)
|
||||
|
||||
def _get_vectorstore(self, collection_name: str):
|
||||
return Chroma(
|
||||
persist_directory=self.persist_directory,
|
||||
embedding_function=self.embeddings,
|
||||
collection_name=collection_name
|
||||
)
|
||||
# return Chroma(
|
||||
# persist_directory=self.persist_directory,
|
||||
# embedding_function=self.embeddings,
|
||||
# collection_name=collection_name
|
||||
# )
|
||||
logger.error("Vector retrieval (Chroma) is temporarily disabled.")
|
||||
return None
|
||||
|
||||
async def query(self, question: str, collection_name: str, top_k: int = 4) -> Dict[str, Any]:
|
||||
"""
|
||||
@ -72,6 +74,8 @@ Helpful Answer:"""
|
||||
start_time = time.time()
|
||||
|
||||
vectorstore = self._get_vectorstore(collection_name)
|
||||
if not vectorstore:
|
||||
return {"query": question, "answer": "Vector store not available.", "source_documents": [], "processing_time_ms": 0}
|
||||
|
||||
qa_chain = RetrievalQA.from_chain_type(
|
||||
llm=self.llm,
|
||||
|
||||
@ -1,115 +0,0 @@
|
||||
"""
|
||||
AudioRecording API Router
|
||||
Enterprise-grade FastAPI router with full CRUD operations
|
||||
Architecture: Routers → Services/CRUD → SQLAlchemy Models + Pydantic Schemas
|
||||
"""
|
||||
from typing import List, Optional
|
||||
from fastapi import APIRouter, Depends, HTTPException, Query, status
|
||||
from sqlalchemy.orm import Session
|
||||
from uuid import UUID
|
||||
|
||||
from src.config.database import get_db
|
||||
from src.services.audio_recording_service import AudioRecordingCRUD
|
||||
from src.validation.audio_recording_schemas import (
|
||||
AudioRecordingCreate,
|
||||
AudioRecordingUpdate,
|
||||
AudioRecordingResponse,
|
||||
AudioRecordingListResponse,
|
||||
)
|
||||
|
||||
router = APIRouter(prefix="/audiorecordings", tags=["AudioRecording"])
|
||||
|
||||
def get_crud(db: Session = Depends(get_db)) -> AudioRecordingCRUD:
|
||||
"""Dependency injection for AudioRecordingCRUD"""
|
||||
return AudioRecordingCRUD(db)
|
||||
|
||||
@router.get("/", response_model=AudioRecordingListResponse)
|
||||
async def list_audio_recordings(
|
||||
skip: int = Query(0, ge=0, description="Number of records to skip"),
|
||||
limit: int = Query(100, ge=1, le=1000, description="Maximum records to return"),
|
||||
crud: AudioRecordingCRUD = Depends(get_crud),
|
||||
):
|
||||
"""
|
||||
List all audiorecordings with pagination and filtering.
|
||||
|
||||
- **skip**: Number of records to skip (for pagination)
|
||||
- **limit**: Maximum number of records to return
|
||||
"""
|
||||
items, total = crud.get_all(skip=skip, limit=limit)
|
||||
|
||||
return AudioRecordingListResponse(
|
||||
items=items,
|
||||
total=total,
|
||||
skip=skip,
|
||||
limit=limit,
|
||||
has_more=skip + limit < total
|
||||
)
|
||||
|
||||
@router.get("/{ audio_recording_id }", response_model=AudioRecordingResponse)
|
||||
async def get_audio_recording(
|
||||
audio_recording_id: UUID,
|
||||
crud: AudioRecordingCRUD = Depends(get_crud),
|
||||
):
|
||||
"""
|
||||
Get a specific audiorecording by ID.
|
||||
|
||||
- **audio_recording_id**: The UUID of the audiorecording
|
||||
"""
|
||||
db_audio_recording = crud.get_by_id(audio_recording_id)
|
||||
if not db_audio_recording:
|
||||
raise HTTPException(
|
||||
status_code=status.HTTP_404_NOT_FOUND,
|
||||
detail=f"AudioRecording with id { audio_recording_id} not found"
|
||||
)
|
||||
return db_audio_recording
|
||||
|
||||
@router.post("/", response_model=AudioRecordingResponse, status_code=status.HTTP_201_CREATED)
|
||||
async def create_audio_recording(
|
||||
audio_recording_in: AudioRecordingCreate,
|
||||
crud: AudioRecordingCRUD = Depends(get_crud),
|
||||
):
|
||||
"""
|
||||
Create a new audiorecording.
|
||||
|
||||
- **audio_recording_in**: The audiorecording data to create
|
||||
"""
|
||||
return crud.create(audio_recording_in)
|
||||
|
||||
@router.put("/{ audio_recording_id }", response_model=AudioRecordingResponse)
|
||||
async def update_audio_recording(
|
||||
audio_recording_id: UUID,
|
||||
audio_recording_in: AudioRecordingUpdate,
|
||||
crud: AudioRecordingCRUD = Depends(get_crud),
|
||||
):
|
||||
"""
|
||||
Update an existing audiorecording.
|
||||
|
||||
- **audio_recording_id**: The UUID of the audiorecording to update
|
||||
- **audio_recording_in**: The updated audiorecording data
|
||||
"""
|
||||
db_audio_recording = crud.get_by_id(audio_recording_id)
|
||||
if not db_audio_recording:
|
||||
raise HTTPException(
|
||||
status_code=status.HTTP_404_NOT_FOUND,
|
||||
detail=f"AudioRecording with id { audio_recording_id} not found"
|
||||
)
|
||||
return crud.update(audio_recording_id, audio_recording_in)
|
||||
|
||||
@router.delete("/{ audio_recording_id }", status_code=status.HTTP_204_NO_CONTENT)
|
||||
async def delete_audio_recording(
|
||||
audio_recording_id: UUID,
|
||||
crud: AudioRecordingCRUD = Depends(get_crud),
|
||||
):
|
||||
"""
|
||||
Delete a audiorecording.
|
||||
|
||||
- **audio_recording_id**: The UUID of the audiorecording to delete
|
||||
"""
|
||||
db_audio_recording = crud.get_by_id(audio_recording_id)
|
||||
if not db_audio_recording:
|
||||
raise HTTPException(
|
||||
status_code=status.HTTP_404_NOT_FOUND,
|
||||
detail=f"AudioRecording with id { audio_recording_id} not found"
|
||||
)
|
||||
crud.delete(audio_recording_id)
|
||||
return None
|
||||
@ -35,7 +35,7 @@ async def list_audio_recordings(
|
||||
- **skip**: Number of records to skip (for pagination)
|
||||
- **limit**: Maximum number of records to return
|
||||
"""
|
||||
items, total = crud.get_all(skip=skip, limit=limit)
|
||||
items, total = await crud.get_all(skip=skip, limit=limit)
|
||||
|
||||
return AudioRecordingListResponse(
|
||||
items=items,
|
||||
@ -55,7 +55,7 @@ async def get_audio_recording(
|
||||
|
||||
- **audio_recording_id**: The UUID of the audiorecording
|
||||
"""
|
||||
db_audio_recording = crud.get_by_id(audio_recording_id)
|
||||
db_audio_recording = await crud.get_by_id(audio_recording_id)
|
||||
if not db_audio_recording:
|
||||
raise HTTPException(
|
||||
status_code=status.HTTP_404_NOT_FOUND,
|
||||
@ -73,7 +73,7 @@ async def create_audio_recording(
|
||||
|
||||
- **audio_recording_in**: The audiorecording data to create
|
||||
"""
|
||||
return crud.create(audio_recording_in)
|
||||
return await crud.create(audio_recording_in)
|
||||
|
||||
@router.put("/{ audio_recording_id }", response_model=AudioRecordingResponse)
|
||||
async def update_audio_recording(
|
||||
@ -87,13 +87,13 @@ async def update_audio_recording(
|
||||
- **audio_recording_id**: The UUID of the audiorecording to update
|
||||
- **audio_recording_in**: The updated audiorecording data
|
||||
"""
|
||||
db_audio_recording = crud.get_by_id(audio_recording_id)
|
||||
db_audio_recording = await crud.get_by_id(audio_recording_id)
|
||||
if not db_audio_recording:
|
||||
raise HTTPException(
|
||||
status_code=status.HTTP_404_NOT_FOUND,
|
||||
detail=f"AudioRecording with id { audio_recording_id} not found"
|
||||
)
|
||||
return crud.update(audio_recording_id, audio_recording_in)
|
||||
return await crud.update(audio_recording_id, audio_recording_in)
|
||||
|
||||
@router.delete("/{ audio_recording_id }", status_code=status.HTTP_204_NO_CONTENT)
|
||||
async def delete_audio_recording(
|
||||
@ -105,11 +105,11 @@ async def delete_audio_recording(
|
||||
|
||||
- **audio_recording_id**: The UUID of the audiorecording to delete
|
||||
"""
|
||||
db_audio_recording = crud.get_by_id(audio_recording_id)
|
||||
db_audio_recording = await crud.get_by_id(audio_recording_id)
|
||||
if not db_audio_recording:
|
||||
raise HTTPException(
|
||||
status_code=status.HTTP_404_NOT_FOUND,
|
||||
detail=f"AudioRecording with id { audio_recording_id} not found"
|
||||
)
|
||||
crud.delete(audio_recording_id)
|
||||
await crud.delete(audio_recording_id)
|
||||
return None
|
||||
|
||||
@ -1,115 +0,0 @@
|
||||
"""
|
||||
AuditLog API Router
|
||||
Enterprise-grade FastAPI router with full CRUD operations
|
||||
Architecture: Routers → Services/CRUD → SQLAlchemy Models + Pydantic Schemas
|
||||
"""
|
||||
from typing import List, Optional
|
||||
from fastapi import APIRouter, Depends, HTTPException, Query, status
|
||||
from sqlalchemy.orm import Session
|
||||
from uuid import UUID
|
||||
|
||||
from src.config.database import get_db
|
||||
from src.services.audit_log_service import AuditLogCRUD
|
||||
from src.validation.audit_log_schemas import (
|
||||
AuditLogCreate,
|
||||
AuditLogUpdate,
|
||||
AuditLogResponse,
|
||||
AuditLogListResponse,
|
||||
)
|
||||
|
||||
router = APIRouter(prefix="/auditlogs", tags=["AuditLog"])
|
||||
|
||||
def get_crud(db: Session = Depends(get_db)) -> AuditLogCRUD:
|
||||
"""Dependency injection for AuditLogCRUD"""
|
||||
return AuditLogCRUD(db)
|
||||
|
||||
@router.get("/", response_model=AuditLogListResponse)
|
||||
async def list_audit_logs(
|
||||
skip: int = Query(0, ge=0, description="Number of records to skip"),
|
||||
limit: int = Query(100, ge=1, le=1000, description="Maximum records to return"),
|
||||
crud: AuditLogCRUD = Depends(get_crud),
|
||||
):
|
||||
"""
|
||||
List all auditlogs with pagination and filtering.
|
||||
|
||||
- **skip**: Number of records to skip (for pagination)
|
||||
- **limit**: Maximum number of records to return
|
||||
"""
|
||||
items, total = crud.get_all(skip=skip, limit=limit)
|
||||
|
||||
return AuditLogListResponse(
|
||||
items=items,
|
||||
total=total,
|
||||
skip=skip,
|
||||
limit=limit,
|
||||
has_more=skip + limit < total
|
||||
)
|
||||
|
||||
@router.get("/{ audit_log_id }", response_model=AuditLogResponse)
|
||||
async def get_audit_log(
|
||||
audit_log_id: UUID,
|
||||
crud: AuditLogCRUD = Depends(get_crud),
|
||||
):
|
||||
"""
|
||||
Get a specific auditlog by ID.
|
||||
|
||||
- **audit_log_id**: The UUID of the auditlog
|
||||
"""
|
||||
db_audit_log = crud.get_by_id(audit_log_id)
|
||||
if not db_audit_log:
|
||||
raise HTTPException(
|
||||
status_code=status.HTTP_404_NOT_FOUND,
|
||||
detail=f"AuditLog with id { audit_log_id} not found"
|
||||
)
|
||||
return db_audit_log
|
||||
|
||||
@router.post("/", response_model=AuditLogResponse, status_code=status.HTTP_201_CREATED)
|
||||
async def create_audit_log(
|
||||
audit_log_in: AuditLogCreate,
|
||||
crud: AuditLogCRUD = Depends(get_crud),
|
||||
):
|
||||
"""
|
||||
Create a new auditlog.
|
||||
|
||||
- **audit_log_in**: The auditlog data to create
|
||||
"""
|
||||
return crud.create(audit_log_in)
|
||||
|
||||
@router.put("/{ audit_log_id }", response_model=AuditLogResponse)
|
||||
async def update_audit_log(
|
||||
audit_log_id: UUID,
|
||||
audit_log_in: AuditLogUpdate,
|
||||
crud: AuditLogCRUD = Depends(get_crud),
|
||||
):
|
||||
"""
|
||||
Update an existing auditlog.
|
||||
|
||||
- **audit_log_id**: The UUID of the auditlog to update
|
||||
- **audit_log_in**: The updated auditlog data
|
||||
"""
|
||||
db_audit_log = crud.get_by_id(audit_log_id)
|
||||
if not db_audit_log:
|
||||
raise HTTPException(
|
||||
status_code=status.HTTP_404_NOT_FOUND,
|
||||
detail=f"AuditLog with id { audit_log_id} not found"
|
||||
)
|
||||
return crud.update(audit_log_id, audit_log_in)
|
||||
|
||||
@router.delete("/{ audit_log_id }", status_code=status.HTTP_204_NO_CONTENT)
|
||||
async def delete_audit_log(
|
||||
audit_log_id: UUID,
|
||||
crud: AuditLogCRUD = Depends(get_crud),
|
||||
):
|
||||
"""
|
||||
Delete a auditlog.
|
||||
|
||||
- **audit_log_id**: The UUID of the auditlog to delete
|
||||
"""
|
||||
db_audit_log = crud.get_by_id(audit_log_id)
|
||||
if not db_audit_log:
|
||||
raise HTTPException(
|
||||
status_code=status.HTTP_404_NOT_FOUND,
|
||||
detail=f"AuditLog with id { audit_log_id} not found"
|
||||
)
|
||||
crud.delete(audit_log_id)
|
||||
return None
|
||||
@ -35,7 +35,7 @@ async def list_audit_logs(
|
||||
- **skip**: Number of records to skip (for pagination)
|
||||
- **limit**: Maximum number of records to return
|
||||
"""
|
||||
items, total = crud.get_all(skip=skip, limit=limit)
|
||||
items, total = await crud.get_all(skip=skip, limit=limit)
|
||||
|
||||
return AuditLogListResponse(
|
||||
items=items,
|
||||
@ -55,7 +55,7 @@ async def get_audit_log(
|
||||
|
||||
- **audit_log_id**: The UUID of the auditlog
|
||||
"""
|
||||
db_audit_log = crud.get_by_id(audit_log_id)
|
||||
db_audit_log = await crud.get_by_id(audit_log_id)
|
||||
if not db_audit_log:
|
||||
raise HTTPException(
|
||||
status_code=status.HTTP_404_NOT_FOUND,
|
||||
@ -73,7 +73,7 @@ async def create_audit_log(
|
||||
|
||||
- **audit_log_in**: The auditlog data to create
|
||||
"""
|
||||
return crud.create(audit_log_in)
|
||||
return await crud.create(audit_log_in)
|
||||
|
||||
@router.put("/{ audit_log_id }", response_model=AuditLogResponse)
|
||||
async def update_audit_log(
|
||||
@ -87,13 +87,13 @@ async def update_audit_log(
|
||||
- **audit_log_id**: The UUID of the auditlog to update
|
||||
- **audit_log_in**: The updated auditlog data
|
||||
"""
|
||||
db_audit_log = crud.get_by_id(audit_log_id)
|
||||
db_audit_log = await crud.get_by_id(audit_log_id)
|
||||
if not db_audit_log:
|
||||
raise HTTPException(
|
||||
status_code=status.HTTP_404_NOT_FOUND,
|
||||
detail=f"AuditLog with id { audit_log_id} not found"
|
||||
)
|
||||
return crud.update(audit_log_id, audit_log_in)
|
||||
return await crud.update(audit_log_id, audit_log_in)
|
||||
|
||||
@router.delete("/{ audit_log_id }", status_code=status.HTTP_204_NO_CONTENT)
|
||||
async def delete_audit_log(
|
||||
@ -105,11 +105,11 @@ async def delete_audit_log(
|
||||
|
||||
- **audit_log_id**: The UUID of the auditlog to delete
|
||||
"""
|
||||
db_audit_log = crud.get_by_id(audit_log_id)
|
||||
db_audit_log = await crud.get_by_id(audit_log_id)
|
||||
if not db_audit_log:
|
||||
raise HTTPException(
|
||||
status_code=status.HTTP_404_NOT_FOUND,
|
||||
detail=f"AuditLog with id { audit_log_id} not found"
|
||||
)
|
||||
crud.delete(audit_log_id)
|
||||
await crud.delete(audit_log_id)
|
||||
return None
|
||||
|
||||
@ -1,115 +1,84 @@
|
||||
"""
|
||||
User API Router
|
||||
Enterprise-grade FastAPI router with full CRUD operations
|
||||
Architecture: Routers → Services/CRUD → SQLAlchemy Models + Pydantic Schemas
|
||||
"""
|
||||
from typing import List, Optional
|
||||
from fastapi import APIRouter, Depends, HTTPException, Query, status
|
||||
from fastapi import APIRouter, Depends, HTTPException, status
|
||||
from sqlalchemy.orm import Session
|
||||
from uuid import UUID
|
||||
|
||||
from src.config.database import get_db
|
||||
from src.services.user_service import UserCRUD
|
||||
from src.validation.user_schemas import (
|
||||
UserCreate,
|
||||
UserUpdate,
|
||||
UserResponse,
|
||||
UserListResponse,
|
||||
from src.validation.auth_schemas import (
|
||||
LoginRequest,
|
||||
RegisterRequest,
|
||||
RefreshTokenRequest,
|
||||
ForgotPasswordRequest,
|
||||
ResetPasswordRequest,
|
||||
ChangePasswordRequest,
|
||||
Token
|
||||
)
|
||||
from src.validation.user_schemas import UserResponse
|
||||
|
||||
router = APIRouter(prefix="/users", tags=["User"])
|
||||
router = APIRouter(prefix="/auth", tags=["Auth"])
|
||||
|
||||
def get_crud(db: Session = Depends(get_db)) -> UserCRUD:
|
||||
"""Dependency injection for UserCRUD"""
|
||||
def get_user_service(db: Session = Depends(get_db)) -> UserCRUD:
|
||||
return UserCRUD(db)
|
||||
|
||||
@router.get("/", response_model=UserListResponse)
|
||||
async def list_users(
|
||||
skip: int = Query(0, ge=0, description="Number of records to skip"),
|
||||
limit: int = Query(100, ge=1, le=1000, description="Maximum records to return"),
|
||||
crud: UserCRUD = Depends(get_crud),
|
||||
@router.post("/register", response_model=UserResponse, status_code=status.HTTP_201_CREATED)
|
||||
async def register(
|
||||
user_in: RegisterRequest,
|
||||
service: UserCRUD = Depends(get_user_service)
|
||||
):
|
||||
"""
|
||||
List all users with pagination and filtering.
|
||||
|
||||
- **skip**: Number of records to skip (for pagination)
|
||||
- **limit**: Maximum number of records to return
|
||||
"""
|
||||
items, total = crud.get_all(skip=skip, limit=limit)
|
||||
|
||||
return UserListResponse(
|
||||
items=items,
|
||||
total=total,
|
||||
skip=skip,
|
||||
limit=limit,
|
||||
has_more=skip + limit < total
|
||||
# Map RegisterRequest to UserCreate for the service
|
||||
from src.validation.user_schemas import UserCreate
|
||||
user_create = UserCreate(
|
||||
username=user_in.username,
|
||||
email=user_in.email,
|
||||
password_hash=user_in.password, # UserService hashes it
|
||||
first_name=user_in.first_name,
|
||||
last_name=user_in.last_name,
|
||||
role=user_in.role,
|
||||
specialty=user_in.specialty,
|
||||
npi=user_in.npi,
|
||||
is_active=True
|
||||
)
|
||||
return await service.create(user_create)
|
||||
|
||||
@router.get("/{ user_id }", response_model=UserResponse)
|
||||
async def get_user(
|
||||
user_id: UUID,
|
||||
crud: UserCRUD = Depends(get_crud),
|
||||
@router.post("/login")
|
||||
async def login(
|
||||
login_data: LoginRequest,
|
||||
service: UserCRUD = Depends(get_user_service)
|
||||
):
|
||||
"""
|
||||
Get a specific user by ID.
|
||||
|
||||
- **user_id**: The UUID of the user
|
||||
"""
|
||||
db_user = crud.get_by_id(user_id)
|
||||
if not db_user:
|
||||
raise HTTPException(
|
||||
status_code=status.HTTP_404_NOT_FOUND,
|
||||
detail=f"User with id { user_id} not found"
|
||||
)
|
||||
return db_user
|
||||
return await service.login(login_data.username, login_data.password)
|
||||
|
||||
@router.post("/", response_model=UserResponse, status_code=status.HTTP_201_CREATED)
|
||||
async def create_user(
|
||||
user_in: UserCreate,
|
||||
crud: UserCRUD = Depends(get_crud),
|
||||
):
|
||||
"""
|
||||
Create a new user.
|
||||
|
||||
- **user_in**: The user data to create
|
||||
"""
|
||||
return crud.create(user_in)
|
||||
@router.post("/logout")
|
||||
async def logout():
|
||||
return {"message": "Successfully logged out"}
|
||||
|
||||
@router.put("/{ user_id }", response_model=UserResponse)
|
||||
async def update_user(
|
||||
user_id: UUID,
|
||||
user_in: UserUpdate,
|
||||
crud: UserCRUD = Depends(get_crud),
|
||||
@router.post("/refresh")
|
||||
async def refresh_token(
|
||||
refresh_data: RefreshTokenRequest,
|
||||
service: UserCRUD = Depends(get_user_service)
|
||||
):
|
||||
"""
|
||||
Update an existing user.
|
||||
|
||||
- **user_id**: The UUID of the user to update
|
||||
- **user_in**: The updated user data
|
||||
"""
|
||||
db_user = crud.get_by_id(user_id)
|
||||
if not db_user:
|
||||
raise HTTPException(
|
||||
status_code=status.HTTP_404_NOT_FOUND,
|
||||
detail=f"User with id { user_id} not found"
|
||||
)
|
||||
return crud.update(user_id, user_in)
|
||||
return await service.refreshToken(refresh_data.refresh_token)
|
||||
|
||||
@router.delete("/{ user_id }", status_code=status.HTTP_204_NO_CONTENT)
|
||||
async def delete_user(
|
||||
user_id: UUID,
|
||||
crud: UserCRUD = Depends(get_crud),
|
||||
@router.post("/forgot-password")
|
||||
async def forgot_password(
|
||||
data: ForgotPasswordRequest,
|
||||
service: UserCRUD = Depends(get_user_service)
|
||||
):
|
||||
"""
|
||||
Delete a user.
|
||||
|
||||
- **user_id**: The UUID of the user to delete
|
||||
"""
|
||||
db_user = crud.get_by_id(user_id)
|
||||
if not db_user:
|
||||
raise HTTPException(
|
||||
status_code=status.HTTP_404_NOT_FOUND,
|
||||
detail=f"User with id { user_id} not found"
|
||||
)
|
||||
crud.delete(user_id)
|
||||
return None
|
||||
return await service.forgotPassword(data.email)
|
||||
|
||||
@router.post("/reset-password")
|
||||
async def reset_password(
|
||||
data: ResetPasswordRequest,
|
||||
service: UserCRUD = Depends(get_user_service)
|
||||
):
|
||||
return await service.resetPassword(data.token, data.new_password)
|
||||
|
||||
@router.post("/change-password")
|
||||
async def change_password(
|
||||
data: ChangePasswordRequest,
|
||||
service: UserCRUD = Depends(get_user_service)
|
||||
):
|
||||
return await service.changePassword(data.current_password, data.new_password)
|
||||
|
||||
@router.get("/me", response_model=UserResponse)
|
||||
async def get_me(service: UserCRUD = Depends(get_user_service)):
|
||||
# This usually requires a security dependency to get current user
|
||||
# For alignment purposes, we'll keep it simple or hook into service
|
||||
return await service.get_current_user()
|
||||
|
||||
@ -35,7 +35,7 @@ async def list_claim_reviews(
|
||||
- **skip**: Number of records to skip (for pagination)
|
||||
- **limit**: Maximum number of records to return
|
||||
"""
|
||||
items, total = crud.get_all(skip=skip, limit=limit)
|
||||
items, total = await crud.get_all(skip=skip, limit=limit)
|
||||
|
||||
return ClaimReviewListResponse(
|
||||
items=items,
|
||||
@ -55,7 +55,7 @@ async def get_claim_review(
|
||||
|
||||
- **claim_review_id**: The UUID of the claimreview
|
||||
"""
|
||||
db_claim_review = crud.get_by_id(claim_review_id)
|
||||
db_claim_review = await crud.get_by_id(claim_review_id)
|
||||
if not db_claim_review:
|
||||
raise HTTPException(
|
||||
status_code=status.HTTP_404_NOT_FOUND,
|
||||
@ -73,7 +73,7 @@ async def create_claim_review(
|
||||
|
||||
- **claim_review_in**: The claimreview data to create
|
||||
"""
|
||||
return crud.create(claim_review_in)
|
||||
return await crud.create(claim_review_in)
|
||||
|
||||
@router.put("/{ claim_review_id }", response_model=ClaimReviewResponse)
|
||||
async def update_claim_review(
|
||||
@ -87,13 +87,13 @@ async def update_claim_review(
|
||||
- **claim_review_id**: The UUID of the claimreview to update
|
||||
- **claim_review_in**: The updated claimreview data
|
||||
"""
|
||||
db_claim_review = crud.get_by_id(claim_review_id)
|
||||
db_claim_review = await crud.get_by_id(claim_review_id)
|
||||
if not db_claim_review:
|
||||
raise HTTPException(
|
||||
status_code=status.HTTP_404_NOT_FOUND,
|
||||
detail=f"ClaimReview with id { claim_review_id} not found"
|
||||
)
|
||||
return crud.update(claim_review_id, claim_review_in)
|
||||
return await crud.update(claim_review_id, claim_review_in)
|
||||
|
||||
@router.delete("/{ claim_review_id }", status_code=status.HTTP_204_NO_CONTENT)
|
||||
async def delete_claim_review(
|
||||
@ -105,11 +105,11 @@ async def delete_claim_review(
|
||||
|
||||
- **claim_review_id**: The UUID of the claimreview to delete
|
||||
"""
|
||||
db_claim_review = crud.get_by_id(claim_review_id)
|
||||
db_claim_review = await crud.get_by_id(claim_review_id)
|
||||
if not db_claim_review:
|
||||
raise HTTPException(
|
||||
status_code=status.HTTP_404_NOT_FOUND,
|
||||
detail=f"ClaimReview with id { claim_review_id} not found"
|
||||
)
|
||||
crud.delete(claim_review_id)
|
||||
await crud.delete(claim_review_id)
|
||||
return None
|
||||
|
||||
@ -35,7 +35,7 @@ async def list_claims(
|
||||
- **skip**: Number of records to skip (for pagination)
|
||||
- **limit**: Maximum number of records to return
|
||||
"""
|
||||
items, total = crud.get_all(skip=skip, limit=limit)
|
||||
items, total = await crud.get_all(skip=skip, limit=limit)
|
||||
|
||||
return ClaimListResponse(
|
||||
items=items,
|
||||
@ -55,7 +55,7 @@ async def get_claim(
|
||||
|
||||
- **claim_id**: The UUID of the claim
|
||||
"""
|
||||
db_claim = crud.get_by_id(claim_id)
|
||||
db_claim = await crud.get_by_id(claim_id)
|
||||
if not db_claim:
|
||||
raise HTTPException(
|
||||
status_code=status.HTTP_404_NOT_FOUND,
|
||||
@ -73,7 +73,7 @@ async def create_claim(
|
||||
|
||||
- **claim_in**: The claim data to create
|
||||
"""
|
||||
return crud.create(claim_in)
|
||||
return await crud.create(claim_in)
|
||||
|
||||
@router.put("/{ claim_id }", response_model=ClaimResponse)
|
||||
async def update_claim(
|
||||
@ -87,13 +87,13 @@ async def update_claim(
|
||||
- **claim_id**: The UUID of the claim to update
|
||||
- **claim_in**: The updated claim data
|
||||
"""
|
||||
db_claim = crud.get_by_id(claim_id)
|
||||
db_claim = await crud.get_by_id(claim_id)
|
||||
if not db_claim:
|
||||
raise HTTPException(
|
||||
status_code=status.HTTP_404_NOT_FOUND,
|
||||
detail=f"Claim with id { claim_id} not found"
|
||||
)
|
||||
return crud.update(claim_id, claim_in)
|
||||
return await crud.update(claim_id, claim_in)
|
||||
|
||||
@router.delete("/{ claim_id }", status_code=status.HTTP_204_NO_CONTENT)
|
||||
async def delete_claim(
|
||||
@ -105,11 +105,11 @@ async def delete_claim(
|
||||
|
||||
- **claim_id**: The UUID of the claim to delete
|
||||
"""
|
||||
db_claim = crud.get_by_id(claim_id)
|
||||
db_claim = await crud.get_by_id(claim_id)
|
||||
if not db_claim:
|
||||
raise HTTPException(
|
||||
status_code=status.HTTP_404_NOT_FOUND,
|
||||
detail=f"Claim with id { claim_id} not found"
|
||||
)
|
||||
crud.delete(claim_id)
|
||||
await crud.delete(claim_id)
|
||||
return None
|
||||
|
||||
@ -1,115 +0,0 @@
|
||||
"""
|
||||
ClaimScrubResult API Router
|
||||
Enterprise-grade FastAPI router with full CRUD operations
|
||||
Architecture: Routers → Services/CRUD → SQLAlchemy Models + Pydantic Schemas
|
||||
"""
|
||||
from typing import List, Optional
|
||||
from fastapi import APIRouter, Depends, HTTPException, Query, status
|
||||
from sqlalchemy.orm import Session
|
||||
from uuid import UUID
|
||||
|
||||
from src.config.database import get_db
|
||||
from src.services.claim_scrub_result_service import ClaimScrubResultCRUD
|
||||
from src.validation.claim_scrub_result_schemas import (
|
||||
ClaimScrubResultCreate,
|
||||
ClaimScrubResultUpdate,
|
||||
ClaimScrubResultResponse,
|
||||
ClaimScrubResultListResponse,
|
||||
)
|
||||
|
||||
router = APIRouter(prefix="/claimscrubresults", tags=["ClaimScrubResult"])
|
||||
|
||||
def get_crud(db: Session = Depends(get_db)) -> ClaimScrubResultCRUD:
|
||||
"""Dependency injection for ClaimScrubResultCRUD"""
|
||||
return ClaimScrubResultCRUD(db)
|
||||
|
||||
@router.get("/", response_model=ClaimScrubResultListResponse)
|
||||
async def list_claim_scrub_results(
|
||||
skip: int = Query(0, ge=0, description="Number of records to skip"),
|
||||
limit: int = Query(100, ge=1, le=1000, description="Maximum records to return"),
|
||||
crud: ClaimScrubResultCRUD = Depends(get_crud),
|
||||
):
|
||||
"""
|
||||
List all claimscrubresults with pagination and filtering.
|
||||
|
||||
- **skip**: Number of records to skip (for pagination)
|
||||
- **limit**: Maximum number of records to return
|
||||
"""
|
||||
items, total = crud.get_all(skip=skip, limit=limit)
|
||||
|
||||
return ClaimScrubResultListResponse(
|
||||
items=items,
|
||||
total=total,
|
||||
skip=skip,
|
||||
limit=limit,
|
||||
has_more=skip + limit < total
|
||||
)
|
||||
|
||||
@router.get("/{ claim_scrub_result_id }", response_model=ClaimScrubResultResponse)
|
||||
async def get_claim_scrub_result(
|
||||
claim_scrub_result_id: UUID,
|
||||
crud: ClaimScrubResultCRUD = Depends(get_crud),
|
||||
):
|
||||
"""
|
||||
Get a specific claimscrubresult by ID.
|
||||
|
||||
- **claim_scrub_result_id**: The UUID of the claimscrubresult
|
||||
"""
|
||||
db_claim_scrub_result = crud.get_by_id(claim_scrub_result_id)
|
||||
if not db_claim_scrub_result:
|
||||
raise HTTPException(
|
||||
status_code=status.HTTP_404_NOT_FOUND,
|
||||
detail=f"ClaimScrubResult with id { claim_scrub_result_id} not found"
|
||||
)
|
||||
return db_claim_scrub_result
|
||||
|
||||
@router.post("/", response_model=ClaimScrubResultResponse, status_code=status.HTTP_201_CREATED)
|
||||
async def create_claim_scrub_result(
|
||||
claim_scrub_result_in: ClaimScrubResultCreate,
|
||||
crud: ClaimScrubResultCRUD = Depends(get_crud),
|
||||
):
|
||||
"""
|
||||
Create a new claimscrubresult.
|
||||
|
||||
- **claim_scrub_result_in**: The claimscrubresult data to create
|
||||
"""
|
||||
return crud.create(claim_scrub_result_in)
|
||||
|
||||
@router.put("/{ claim_scrub_result_id }", response_model=ClaimScrubResultResponse)
|
||||
async def update_claim_scrub_result(
|
||||
claim_scrub_result_id: UUID,
|
||||
claim_scrub_result_in: ClaimScrubResultUpdate,
|
||||
crud: ClaimScrubResultCRUD = Depends(get_crud),
|
||||
):
|
||||
"""
|
||||
Update an existing claimscrubresult.
|
||||
|
||||
- **claim_scrub_result_id**: The UUID of the claimscrubresult to update
|
||||
- **claim_scrub_result_in**: The updated claimscrubresult data
|
||||
"""
|
||||
db_claim_scrub_result = crud.get_by_id(claim_scrub_result_id)
|
||||
if not db_claim_scrub_result:
|
||||
raise HTTPException(
|
||||
status_code=status.HTTP_404_NOT_FOUND,
|
||||
detail=f"ClaimScrubResult with id { claim_scrub_result_id} not found"
|
||||
)
|
||||
return crud.update(claim_scrub_result_id, claim_scrub_result_in)
|
||||
|
||||
@router.delete("/{ claim_scrub_result_id }", status_code=status.HTTP_204_NO_CONTENT)
|
||||
async def delete_claim_scrub_result(
|
||||
claim_scrub_result_id: UUID,
|
||||
crud: ClaimScrubResultCRUD = Depends(get_crud),
|
||||
):
|
||||
"""
|
||||
Delete a claimscrubresult.
|
||||
|
||||
- **claim_scrub_result_id**: The UUID of the claimscrubresult to delete
|
||||
"""
|
||||
db_claim_scrub_result = crud.get_by_id(claim_scrub_result_id)
|
||||
if not db_claim_scrub_result:
|
||||
raise HTTPException(
|
||||
status_code=status.HTTP_404_NOT_FOUND,
|
||||
detail=f"ClaimScrubResult with id { claim_scrub_result_id} not found"
|
||||
)
|
||||
crud.delete(claim_scrub_result_id)
|
||||
return None
|
||||
@ -35,7 +35,7 @@ async def list_claim_scrub_results(
|
||||
- **skip**: Number of records to skip (for pagination)
|
||||
- **limit**: Maximum number of records to return
|
||||
"""
|
||||
items, total = crud.get_all(skip=skip, limit=limit)
|
||||
items, total = await crud.get_all(skip=skip, limit=limit)
|
||||
|
||||
return ClaimScrubResultListResponse(
|
||||
items=items,
|
||||
@ -55,7 +55,7 @@ async def get_claim_scrub_result(
|
||||
|
||||
- **claim_scrub_result_id**: The UUID of the claimscrubresult
|
||||
"""
|
||||
db_claim_scrub_result = crud.get_by_id(claim_scrub_result_id)
|
||||
db_claim_scrub_result = await crud.get_by_id(claim_scrub_result_id)
|
||||
if not db_claim_scrub_result:
|
||||
raise HTTPException(
|
||||
status_code=status.HTTP_404_NOT_FOUND,
|
||||
@ -73,7 +73,7 @@ async def create_claim_scrub_result(
|
||||
|
||||
- **claim_scrub_result_in**: The claimscrubresult data to create
|
||||
"""
|
||||
return crud.create(claim_scrub_result_in)
|
||||
return await crud.create(claim_scrub_result_in)
|
||||
|
||||
@router.put("/{ claim_scrub_result_id }", response_model=ClaimScrubResultResponse)
|
||||
async def update_claim_scrub_result(
|
||||
@ -87,13 +87,13 @@ async def update_claim_scrub_result(
|
||||
- **claim_scrub_result_id**: The UUID of the claimscrubresult to update
|
||||
- **claim_scrub_result_in**: The updated claimscrubresult data
|
||||
"""
|
||||
db_claim_scrub_result = crud.get_by_id(claim_scrub_result_id)
|
||||
db_claim_scrub_result = await crud.get_by_id(claim_scrub_result_id)
|
||||
if not db_claim_scrub_result:
|
||||
raise HTTPException(
|
||||
status_code=status.HTTP_404_NOT_FOUND,
|
||||
detail=f"ClaimScrubResult with id { claim_scrub_result_id} not found"
|
||||
)
|
||||
return crud.update(claim_scrub_result_id, claim_scrub_result_in)
|
||||
return await crud.update(claim_scrub_result_id, claim_scrub_result_in)
|
||||
|
||||
@router.delete("/{ claim_scrub_result_id }", status_code=status.HTTP_204_NO_CONTENT)
|
||||
async def delete_claim_scrub_result(
|
||||
@ -105,11 +105,11 @@ async def delete_claim_scrub_result(
|
||||
|
||||
- **claim_scrub_result_id**: The UUID of the claimscrubresult to delete
|
||||
"""
|
||||
db_claim_scrub_result = crud.get_by_id(claim_scrub_result_id)
|
||||
db_claim_scrub_result = await crud.get_by_id(claim_scrub_result_id)
|
||||
if not db_claim_scrub_result:
|
||||
raise HTTPException(
|
||||
status_code=status.HTTP_404_NOT_FOUND,
|
||||
detail=f"ClaimScrubResult with id { claim_scrub_result_id} not found"
|
||||
)
|
||||
crud.delete(claim_scrub_result_id)
|
||||
await crud.delete(claim_scrub_result_id)
|
||||
return None
|
||||
|
||||
@ -35,7 +35,7 @@ async def list_clinical_entities(
|
||||
- **skip**: Number of records to skip (for pagination)
|
||||
- **limit**: Maximum number of records to return
|
||||
"""
|
||||
items, total = crud.get_all(skip=skip, limit=limit)
|
||||
items, total = await crud.get_all(skip=skip, limit=limit)
|
||||
|
||||
return ClinicalEntityListResponse(
|
||||
items=items,
|
||||
@ -55,7 +55,7 @@ async def get_clinical_entity(
|
||||
|
||||
- **clinical_entity_id**: The UUID of the clinicalentity
|
||||
"""
|
||||
db_clinical_entity = crud.get_by_id(clinical_entity_id)
|
||||
db_clinical_entity = await crud.get_by_id(clinical_entity_id)
|
||||
if not db_clinical_entity:
|
||||
raise HTTPException(
|
||||
status_code=status.HTTP_404_NOT_FOUND,
|
||||
@ -73,7 +73,7 @@ async def create_clinical_entity(
|
||||
|
||||
- **clinical_entity_in**: The clinicalentity data to create
|
||||
"""
|
||||
return crud.create(clinical_entity_in)
|
||||
return await crud.create(clinical_entity_in)
|
||||
|
||||
@router.put("/{ clinical_entity_id }", response_model=ClinicalEntityResponse)
|
||||
async def update_clinical_entity(
|
||||
@ -87,13 +87,13 @@ async def update_clinical_entity(
|
||||
- **clinical_entity_id**: The UUID of the clinicalentity to update
|
||||
- **clinical_entity_in**: The updated clinicalentity data
|
||||
"""
|
||||
db_clinical_entity = crud.get_by_id(clinical_entity_id)
|
||||
db_clinical_entity = await crud.get_by_id(clinical_entity_id)
|
||||
if not db_clinical_entity:
|
||||
raise HTTPException(
|
||||
status_code=status.HTTP_404_NOT_FOUND,
|
||||
detail=f"ClinicalEntity with id { clinical_entity_id} not found"
|
||||
)
|
||||
return crud.update(clinical_entity_id, clinical_entity_in)
|
||||
return await crud.update(clinical_entity_id, clinical_entity_in)
|
||||
|
||||
@router.delete("/{ clinical_entity_id }", status_code=status.HTTP_204_NO_CONTENT)
|
||||
async def delete_clinical_entity(
|
||||
@ -105,11 +105,11 @@ async def delete_clinical_entity(
|
||||
|
||||
- **clinical_entity_id**: The UUID of the clinicalentity to delete
|
||||
"""
|
||||
db_clinical_entity = crud.get_by_id(clinical_entity_id)
|
||||
db_clinical_entity = await crud.get_by_id(clinical_entity_id)
|
||||
if not db_clinical_entity:
|
||||
raise HTTPException(
|
||||
status_code=status.HTTP_404_NOT_FOUND,
|
||||
detail=f"ClinicalEntity with id { clinical_entity_id} not found"
|
||||
)
|
||||
crud.delete(clinical_entity_id)
|
||||
await crud.delete(clinical_entity_id)
|
||||
return None
|
||||
|
||||
@ -1,115 +0,0 @@
|
||||
"""
|
||||
Claim API Router
|
||||
Enterprise-grade FastAPI router with full CRUD operations
|
||||
Architecture: Routers → Services/CRUD → SQLAlchemy Models + Pydantic Schemas
|
||||
"""
|
||||
from typing import List, Optional
|
||||
from fastapi import APIRouter, Depends, HTTPException, Query, status
|
||||
from sqlalchemy.orm import Session
|
||||
from uuid import UUID
|
||||
|
||||
from src.config.database import get_db
|
||||
from src.services.claim_service import ClaimCRUD
|
||||
from src.validation.claim_schemas import (
|
||||
ClaimCreate,
|
||||
ClaimUpdate,
|
||||
ClaimResponse,
|
||||
ClaimListResponse,
|
||||
)
|
||||
|
||||
router = APIRouter(prefix="/claims", tags=["Claim"])
|
||||
|
||||
def get_crud(db: Session = Depends(get_db)) -> ClaimCRUD:
|
||||
"""Dependency injection for ClaimCRUD"""
|
||||
return ClaimCRUD(db)
|
||||
|
||||
@router.get("/", response_model=ClaimListResponse)
|
||||
async def list_claims(
|
||||
skip: int = Query(0, ge=0, description="Number of records to skip"),
|
||||
limit: int = Query(100, ge=1, le=1000, description="Maximum records to return"),
|
||||
crud: ClaimCRUD = Depends(get_crud),
|
||||
):
|
||||
"""
|
||||
List all claims with pagination and filtering.
|
||||
|
||||
- **skip**: Number of records to skip (for pagination)
|
||||
- **limit**: Maximum number of records to return
|
||||
"""
|
||||
items, total = crud.get_all(skip=skip, limit=limit)
|
||||
|
||||
return ClaimListResponse(
|
||||
items=items,
|
||||
total=total,
|
||||
skip=skip,
|
||||
limit=limit,
|
||||
has_more=skip + limit < total
|
||||
)
|
||||
|
||||
@router.get("/{ claim_id }", response_model=ClaimResponse)
|
||||
async def get_claim(
|
||||
claim_id: UUID,
|
||||
crud: ClaimCRUD = Depends(get_crud),
|
||||
):
|
||||
"""
|
||||
Get a specific claim by ID.
|
||||
|
||||
- **claim_id**: The UUID of the claim
|
||||
"""
|
||||
db_claim = crud.get_by_id(claim_id)
|
||||
if not db_claim:
|
||||
raise HTTPException(
|
||||
status_code=status.HTTP_404_NOT_FOUND,
|
||||
detail=f"Claim with id { claim_id} not found"
|
||||
)
|
||||
return db_claim
|
||||
|
||||
@router.post("/", response_model=ClaimResponse, status_code=status.HTTP_201_CREATED)
|
||||
async def create_claim(
|
||||
claim_in: ClaimCreate,
|
||||
crud: ClaimCRUD = Depends(get_crud),
|
||||
):
|
||||
"""
|
||||
Create a new claim.
|
||||
|
||||
- **claim_in**: The claim data to create
|
||||
"""
|
||||
return crud.create(claim_in)
|
||||
|
||||
@router.put("/{ claim_id }", response_model=ClaimResponse)
|
||||
async def update_claim(
|
||||
claim_id: UUID,
|
||||
claim_in: ClaimUpdate,
|
||||
crud: ClaimCRUD = Depends(get_crud),
|
||||
):
|
||||
"""
|
||||
Update an existing claim.
|
||||
|
||||
- **claim_id**: The UUID of the claim to update
|
||||
- **claim_in**: The updated claim data
|
||||
"""
|
||||
db_claim = crud.get_by_id(claim_id)
|
||||
if not db_claim:
|
||||
raise HTTPException(
|
||||
status_code=status.HTTP_404_NOT_FOUND,
|
||||
detail=f"Claim with id { claim_id} not found"
|
||||
)
|
||||
return crud.update(claim_id, claim_in)
|
||||
|
||||
@router.delete("/{ claim_id }", status_code=status.HTTP_204_NO_CONTENT)
|
||||
async def delete_claim(
|
||||
claim_id: UUID,
|
||||
crud: ClaimCRUD = Depends(get_crud),
|
||||
):
|
||||
"""
|
||||
Delete a claim.
|
||||
|
||||
- **claim_id**: The UUID of the claim to delete
|
||||
"""
|
||||
db_claim = crud.get_by_id(claim_id)
|
||||
if not db_claim:
|
||||
raise HTTPException(
|
||||
status_code=status.HTTP_404_NOT_FOUND,
|
||||
detail=f"Claim with id { claim_id} not found"
|
||||
)
|
||||
crud.delete(claim_id)
|
||||
return None
|
||||
@ -35,7 +35,7 @@ async def list_confidence_scores(
|
||||
- **skip**: Number of records to skip (for pagination)
|
||||
- **limit**: Maximum number of records to return
|
||||
"""
|
||||
items, total = crud.get_all(skip=skip, limit=limit)
|
||||
items, total = await crud.get_all(skip=skip, limit=limit)
|
||||
|
||||
return ConfidenceScoreListResponse(
|
||||
items=items,
|
||||
@ -55,7 +55,7 @@ async def get_confidence_score(
|
||||
|
||||
- **confidence_score_id**: The UUID of the confidencescore
|
||||
"""
|
||||
db_confidence_score = crud.get_by_id(confidence_score_id)
|
||||
db_confidence_score = await crud.get_by_id(confidence_score_id)
|
||||
if not db_confidence_score:
|
||||
raise HTTPException(
|
||||
status_code=status.HTTP_404_NOT_FOUND,
|
||||
@ -73,7 +73,7 @@ async def create_confidence_score(
|
||||
|
||||
- **confidence_score_in**: The confidencescore data to create
|
||||
"""
|
||||
return crud.create(confidence_score_in)
|
||||
return await crud.create(confidence_score_in)
|
||||
|
||||
@router.put("/{ confidence_score_id }", response_model=ConfidenceScoreResponse)
|
||||
async def update_confidence_score(
|
||||
@ -87,13 +87,13 @@ async def update_confidence_score(
|
||||
- **confidence_score_id**: The UUID of the confidencescore to update
|
||||
- **confidence_score_in**: The updated confidencescore data
|
||||
"""
|
||||
db_confidence_score = crud.get_by_id(confidence_score_id)
|
||||
db_confidence_score = await crud.get_by_id(confidence_score_id)
|
||||
if not db_confidence_score:
|
||||
raise HTTPException(
|
||||
status_code=status.HTTP_404_NOT_FOUND,
|
||||
detail=f"ConfidenceScore with id { confidence_score_id} not found"
|
||||
)
|
||||
return crud.update(confidence_score_id, confidence_score_in)
|
||||
return await crud.update(confidence_score_id, confidence_score_in)
|
||||
|
||||
@router.delete("/{ confidence_score_id }", status_code=status.HTTP_204_NO_CONTENT)
|
||||
async def delete_confidence_score(
|
||||
@ -105,11 +105,11 @@ async def delete_confidence_score(
|
||||
|
||||
- **confidence_score_id**: The UUID of the confidencescore to delete
|
||||
"""
|
||||
db_confidence_score = crud.get_by_id(confidence_score_id)
|
||||
db_confidence_score = await crud.get_by_id(confidence_score_id)
|
||||
if not db_confidence_score:
|
||||
raise HTTPException(
|
||||
status_code=status.HTTP_404_NOT_FOUND,
|
||||
detail=f"ConfidenceScore with id { confidence_score_id} not found"
|
||||
)
|
||||
crud.delete(confidence_score_id)
|
||||
await crud.delete(confidence_score_id)
|
||||
return None
|
||||
|
||||
@ -35,7 +35,7 @@ async def list_cpt_codes(
|
||||
- **skip**: Number of records to skip (for pagination)
|
||||
- **limit**: Maximum number of records to return
|
||||
"""
|
||||
items, total = crud.get_all(skip=skip, limit=limit)
|
||||
items, total = await crud.get_all(skip=skip, limit=limit)
|
||||
|
||||
return CPTCodeListResponse(
|
||||
items=items,
|
||||
@ -55,7 +55,7 @@ async def get_cpt_code(
|
||||
|
||||
- **cpt_code_id**: The UUID of the cptcode
|
||||
"""
|
||||
db_cpt_code = crud.get_by_id(cpt_code_id)
|
||||
db_cpt_code = await crud.get_by_id(cpt_code_id)
|
||||
if not db_cpt_code:
|
||||
raise HTTPException(
|
||||
status_code=status.HTTP_404_NOT_FOUND,
|
||||
@ -73,7 +73,7 @@ async def create_cpt_code(
|
||||
|
||||
- **cpt_code_in**: The cptcode data to create
|
||||
"""
|
||||
return crud.create(cpt_code_in)
|
||||
return await crud.create(cpt_code_in)
|
||||
|
||||
@router.put("/{ cpt_code_id }", response_model=CPTCodeResponse)
|
||||
async def update_cpt_code(
|
||||
@ -87,13 +87,13 @@ async def update_cpt_code(
|
||||
- **cpt_code_id**: The UUID of the cptcode to update
|
||||
- **cpt_code_in**: The updated cptcode data
|
||||
"""
|
||||
db_cpt_code = crud.get_by_id(cpt_code_id)
|
||||
db_cpt_code = await crud.get_by_id(cpt_code_id)
|
||||
if not db_cpt_code:
|
||||
raise HTTPException(
|
||||
status_code=status.HTTP_404_NOT_FOUND,
|
||||
detail=f"CPTCode with id { cpt_code_id} not found"
|
||||
)
|
||||
return crud.update(cpt_code_id, cpt_code_in)
|
||||
return await crud.update(cpt_code_id, cpt_code_in)
|
||||
|
||||
@router.delete("/{ cpt_code_id }", status_code=status.HTTP_204_NO_CONTENT)
|
||||
async def delete_cpt_code(
|
||||
@ -105,11 +105,11 @@ async def delete_cpt_code(
|
||||
|
||||
- **cpt_code_id**: The UUID of the cptcode to delete
|
||||
"""
|
||||
db_cpt_code = crud.get_by_id(cpt_code_id)
|
||||
db_cpt_code = await crud.get_by_id(cpt_code_id)
|
||||
if not db_cpt_code:
|
||||
raise HTTPException(
|
||||
status_code=status.HTTP_404_NOT_FOUND,
|
||||
detail=f"CPTCode with id { cpt_code_id} not found"
|
||||
)
|
||||
crud.delete(cpt_code_id)
|
||||
await crud.delete(cpt_code_id)
|
||||
return None
|
||||
|
||||
@ -35,7 +35,7 @@ async def list_cpt_modifiers(
|
||||
- **skip**: Number of records to skip (for pagination)
|
||||
- **limit**: Maximum number of records to return
|
||||
"""
|
||||
items, total = crud.get_all(skip=skip, limit=limit)
|
||||
items, total = await crud.get_all(skip=skip, limit=limit)
|
||||
|
||||
return CPTModifierListResponse(
|
||||
items=items,
|
||||
@ -55,7 +55,7 @@ async def get_cpt_modifier(
|
||||
|
||||
- **cpt_modifier_id**: The UUID of the cptmodifier
|
||||
"""
|
||||
db_cpt_modifier = crud.get_by_id(cpt_modifier_id)
|
||||
db_cpt_modifier = await crud.get_by_id(cpt_modifier_id)
|
||||
if not db_cpt_modifier:
|
||||
raise HTTPException(
|
||||
status_code=status.HTTP_404_NOT_FOUND,
|
||||
@ -73,7 +73,7 @@ async def create_cpt_modifier(
|
||||
|
||||
- **cpt_modifier_in**: The cptmodifier data to create
|
||||
"""
|
||||
return crud.create(cpt_modifier_in)
|
||||
return await crud.create(cpt_modifier_in)
|
||||
|
||||
@router.put("/{ cpt_modifier_id }", response_model=CPTModifierResponse)
|
||||
async def update_cpt_modifier(
|
||||
@ -87,13 +87,13 @@ async def update_cpt_modifier(
|
||||
- **cpt_modifier_id**: The UUID of the cptmodifier to update
|
||||
- **cpt_modifier_in**: The updated cptmodifier data
|
||||
"""
|
||||
db_cpt_modifier = crud.get_by_id(cpt_modifier_id)
|
||||
db_cpt_modifier = await crud.get_by_id(cpt_modifier_id)
|
||||
if not db_cpt_modifier:
|
||||
raise HTTPException(
|
||||
status_code=status.HTTP_404_NOT_FOUND,
|
||||
detail=f"CPTModifier with id { cpt_modifier_id} not found"
|
||||
)
|
||||
return crud.update(cpt_modifier_id, cpt_modifier_in)
|
||||
return await crud.update(cpt_modifier_id, cpt_modifier_in)
|
||||
|
||||
@router.delete("/{ cpt_modifier_id }", status_code=status.HTTP_204_NO_CONTENT)
|
||||
async def delete_cpt_modifier(
|
||||
@ -105,11 +105,11 @@ async def delete_cpt_modifier(
|
||||
|
||||
- **cpt_modifier_id**: The UUID of the cptmodifier to delete
|
||||
"""
|
||||
db_cpt_modifier = crud.get_by_id(cpt_modifier_id)
|
||||
db_cpt_modifier = await crud.get_by_id(cpt_modifier_id)
|
||||
if not db_cpt_modifier:
|
||||
raise HTTPException(
|
||||
status_code=status.HTTP_404_NOT_FOUND,
|
||||
detail=f"CPTModifier with id { cpt_modifier_id} not found"
|
||||
)
|
||||
crud.delete(cpt_modifier_id)
|
||||
await crud.delete(cpt_modifier_id)
|
||||
return None
|
||||
|
||||
@ -1,115 +0,0 @@
|
||||
"""
|
||||
DenialPattern API Router
|
||||
Enterprise-grade FastAPI router with full CRUD operations
|
||||
Architecture: Routers → Services/CRUD → SQLAlchemy Models + Pydantic Schemas
|
||||
"""
|
||||
from typing import List, Optional
|
||||
from fastapi import APIRouter, Depends, HTTPException, Query, status
|
||||
from sqlalchemy.orm import Session
|
||||
from uuid import UUID
|
||||
|
||||
from src.config.database import get_db
|
||||
from src.services.denial_pattern_service import DenialPatternCRUD
|
||||
from src.validation.denial_pattern_schemas import (
|
||||
DenialPatternCreate,
|
||||
DenialPatternUpdate,
|
||||
DenialPatternResponse,
|
||||
DenialPatternListResponse,
|
||||
)
|
||||
|
||||
router = APIRouter(prefix="/denialpatterns", tags=["DenialPattern"])
|
||||
|
||||
def get_crud(db: Session = Depends(get_db)) -> DenialPatternCRUD:
|
||||
"""Dependency injection for DenialPatternCRUD"""
|
||||
return DenialPatternCRUD(db)
|
||||
|
||||
@router.get("/", response_model=DenialPatternListResponse)
|
||||
async def list_denial_patterns(
|
||||
skip: int = Query(0, ge=0, description="Number of records to skip"),
|
||||
limit: int = Query(100, ge=1, le=1000, description="Maximum records to return"),
|
||||
crud: DenialPatternCRUD = Depends(get_crud),
|
||||
):
|
||||
"""
|
||||
List all denialpatterns with pagination and filtering.
|
||||
|
||||
- **skip**: Number of records to skip (for pagination)
|
||||
- **limit**: Maximum number of records to return
|
||||
"""
|
||||
items, total = crud.get_all(skip=skip, limit=limit)
|
||||
|
||||
return DenialPatternListResponse(
|
||||
items=items,
|
||||
total=total,
|
||||
skip=skip,
|
||||
limit=limit,
|
||||
has_more=skip + limit < total
|
||||
)
|
||||
|
||||
@router.get("/{ denial_pattern_id }", response_model=DenialPatternResponse)
|
||||
async def get_denial_pattern(
|
||||
denial_pattern_id: UUID,
|
||||
crud: DenialPatternCRUD = Depends(get_crud),
|
||||
):
|
||||
"""
|
||||
Get a specific denialpattern by ID.
|
||||
|
||||
- **denial_pattern_id**: The UUID of the denialpattern
|
||||
"""
|
||||
db_denial_pattern = crud.get_by_id(denial_pattern_id)
|
||||
if not db_denial_pattern:
|
||||
raise HTTPException(
|
||||
status_code=status.HTTP_404_NOT_FOUND,
|
||||
detail=f"DenialPattern with id { denial_pattern_id} not found"
|
||||
)
|
||||
return db_denial_pattern
|
||||
|
||||
@router.post("/", response_model=DenialPatternResponse, status_code=status.HTTP_201_CREATED)
|
||||
async def create_denial_pattern(
|
||||
denial_pattern_in: DenialPatternCreate,
|
||||
crud: DenialPatternCRUD = Depends(get_crud),
|
||||
):
|
||||
"""
|
||||
Create a new denialpattern.
|
||||
|
||||
- **denial_pattern_in**: The denialpattern data to create
|
||||
"""
|
||||
return crud.create(denial_pattern_in)
|
||||
|
||||
@router.put("/{ denial_pattern_id }", response_model=DenialPatternResponse)
|
||||
async def update_denial_pattern(
|
||||
denial_pattern_id: UUID,
|
||||
denial_pattern_in: DenialPatternUpdate,
|
||||
crud: DenialPatternCRUD = Depends(get_crud),
|
||||
):
|
||||
"""
|
||||
Update an existing denialpattern.
|
||||
|
||||
- **denial_pattern_id**: The UUID of the denialpattern to update
|
||||
- **denial_pattern_in**: The updated denialpattern data
|
||||
"""
|
||||
db_denial_pattern = crud.get_by_id(denial_pattern_id)
|
||||
if not db_denial_pattern:
|
||||
raise HTTPException(
|
||||
status_code=status.HTTP_404_NOT_FOUND,
|
||||
detail=f"DenialPattern with id { denial_pattern_id} not found"
|
||||
)
|
||||
return crud.update(denial_pattern_id, denial_pattern_in)
|
||||
|
||||
@router.delete("/{ denial_pattern_id }", status_code=status.HTTP_204_NO_CONTENT)
|
||||
async def delete_denial_pattern(
|
||||
denial_pattern_id: UUID,
|
||||
crud: DenialPatternCRUD = Depends(get_crud),
|
||||
):
|
||||
"""
|
||||
Delete a denialpattern.
|
||||
|
||||
- **denial_pattern_id**: The UUID of the denialpattern to delete
|
||||
"""
|
||||
db_denial_pattern = crud.get_by_id(denial_pattern_id)
|
||||
if not db_denial_pattern:
|
||||
raise HTTPException(
|
||||
status_code=status.HTTP_404_NOT_FOUND,
|
||||
detail=f"DenialPattern with id { denial_pattern_id} not found"
|
||||
)
|
||||
crud.delete(denial_pattern_id)
|
||||
return None
|
||||
@ -35,7 +35,7 @@ async def list_denial_patterns(
|
||||
- **skip**: Number of records to skip (for pagination)
|
||||
- **limit**: Maximum number of records to return
|
||||
"""
|
||||
items, total = crud.get_all(skip=skip, limit=limit)
|
||||
items, total = await crud.get_all(skip=skip, limit=limit)
|
||||
|
||||
return DenialPatternListResponse(
|
||||
items=items,
|
||||
@ -55,7 +55,7 @@ async def get_denial_pattern(
|
||||
|
||||
- **denial_pattern_id**: The UUID of the denialpattern
|
||||
"""
|
||||
db_denial_pattern = crud.get_by_id(denial_pattern_id)
|
||||
db_denial_pattern = await crud.get_by_id(denial_pattern_id)
|
||||
if not db_denial_pattern:
|
||||
raise HTTPException(
|
||||
status_code=status.HTTP_404_NOT_FOUND,
|
||||
@ -73,7 +73,7 @@ async def create_denial_pattern(
|
||||
|
||||
- **denial_pattern_in**: The denialpattern data to create
|
||||
"""
|
||||
return crud.create(denial_pattern_in)
|
||||
return await crud.create(denial_pattern_in)
|
||||
|
||||
@router.put("/{ denial_pattern_id }", response_model=DenialPatternResponse)
|
||||
async def update_denial_pattern(
|
||||
@ -87,13 +87,13 @@ async def update_denial_pattern(
|
||||
- **denial_pattern_id**: The UUID of the denialpattern to update
|
||||
- **denial_pattern_in**: The updated denialpattern data
|
||||
"""
|
||||
db_denial_pattern = crud.get_by_id(denial_pattern_id)
|
||||
db_denial_pattern = await crud.get_by_id(denial_pattern_id)
|
||||
if not db_denial_pattern:
|
||||
raise HTTPException(
|
||||
status_code=status.HTTP_404_NOT_FOUND,
|
||||
detail=f"DenialPattern with id { denial_pattern_id} not found"
|
||||
)
|
||||
return crud.update(denial_pattern_id, denial_pattern_in)
|
||||
return await crud.update(denial_pattern_id, denial_pattern_in)
|
||||
|
||||
@router.delete("/{ denial_pattern_id }", status_code=status.HTTP_204_NO_CONTENT)
|
||||
async def delete_denial_pattern(
|
||||
@ -105,11 +105,11 @@ async def delete_denial_pattern(
|
||||
|
||||
- **denial_pattern_id**: The UUID of the denialpattern to delete
|
||||
"""
|
||||
db_denial_pattern = crud.get_by_id(denial_pattern_id)
|
||||
db_denial_pattern = await crud.get_by_id(denial_pattern_id)
|
||||
if not db_denial_pattern:
|
||||
raise HTTPException(
|
||||
status_code=status.HTTP_404_NOT_FOUND,
|
||||
detail=f"DenialPattern with id { denial_pattern_id} not found"
|
||||
)
|
||||
crud.delete(denial_pattern_id)
|
||||
await crud.delete(denial_pattern_id)
|
||||
return None
|
||||
|
||||
@ -1,115 +0,0 @@
|
||||
"""
|
||||
EMRIntegration API Router
|
||||
Enterprise-grade FastAPI router with full CRUD operations
|
||||
Architecture: Routers → Services/CRUD → SQLAlchemy Models + Pydantic Schemas
|
||||
"""
|
||||
from typing import List, Optional
|
||||
from fastapi import APIRouter, Depends, HTTPException, Query, status
|
||||
from sqlalchemy.orm import Session
|
||||
from uuid import UUID
|
||||
|
||||
from src.config.database import get_db
|
||||
from src.services.emr_integration_service import EMRIntegrationCRUD
|
||||
from src.validation.emr_integration_schemas import (
|
||||
EMRIntegrationCreate,
|
||||
EMRIntegrationUpdate,
|
||||
EMRIntegrationResponse,
|
||||
EMRIntegrationListResponse,
|
||||
)
|
||||
|
||||
router = APIRouter(prefix="/emrintegrations", tags=["EMRIntegration"])
|
||||
|
||||
def get_crud(db: Session = Depends(get_db)) -> EMRIntegrationCRUD:
|
||||
"""Dependency injection for EMRIntegrationCRUD"""
|
||||
return EMRIntegrationCRUD(db)
|
||||
|
||||
@router.get("/", response_model=EMRIntegrationListResponse)
|
||||
async def list_emr_integrations(
|
||||
skip: int = Query(0, ge=0, description="Number of records to skip"),
|
||||
limit: int = Query(100, ge=1, le=1000, description="Maximum records to return"),
|
||||
crud: EMRIntegrationCRUD = Depends(get_crud),
|
||||
):
|
||||
"""
|
||||
List all emrintegrations with pagination and filtering.
|
||||
|
||||
- **skip**: Number of records to skip (for pagination)
|
||||
- **limit**: Maximum number of records to return
|
||||
"""
|
||||
items, total = crud.get_all(skip=skip, limit=limit)
|
||||
|
||||
return EMRIntegrationListResponse(
|
||||
items=items,
|
||||
total=total,
|
||||
skip=skip,
|
||||
limit=limit,
|
||||
has_more=skip + limit < total
|
||||
)
|
||||
|
||||
@router.get("/{ emr_integration_id }", response_model=EMRIntegrationResponse)
|
||||
async def get_emr_integration(
|
||||
emr_integration_id: UUID,
|
||||
crud: EMRIntegrationCRUD = Depends(get_crud),
|
||||
):
|
||||
"""
|
||||
Get a specific emrintegration by ID.
|
||||
|
||||
- **emr_integration_id**: The UUID of the emrintegration
|
||||
"""
|
||||
db_emr_integration = crud.get_by_id(emr_integration_id)
|
||||
if not db_emr_integration:
|
||||
raise HTTPException(
|
||||
status_code=status.HTTP_404_NOT_FOUND,
|
||||
detail=f"EMRIntegration with id { emr_integration_id} not found"
|
||||
)
|
||||
return db_emr_integration
|
||||
|
||||
@router.post("/", response_model=EMRIntegrationResponse, status_code=status.HTTP_201_CREATED)
|
||||
async def create_emr_integration(
|
||||
emr_integration_in: EMRIntegrationCreate,
|
||||
crud: EMRIntegrationCRUD = Depends(get_crud),
|
||||
):
|
||||
"""
|
||||
Create a new emrintegration.
|
||||
|
||||
- **emr_integration_in**: The emrintegration data to create
|
||||
"""
|
||||
return crud.create(emr_integration_in)
|
||||
|
||||
@router.put("/{ emr_integration_id }", response_model=EMRIntegrationResponse)
|
||||
async def update_emr_integration(
|
||||
emr_integration_id: UUID,
|
||||
emr_integration_in: EMRIntegrationUpdate,
|
||||
crud: EMRIntegrationCRUD = Depends(get_crud),
|
||||
):
|
||||
"""
|
||||
Update an existing emrintegration.
|
||||
|
||||
- **emr_integration_id**: The UUID of the emrintegration to update
|
||||
- **emr_integration_in**: The updated emrintegration data
|
||||
"""
|
||||
db_emr_integration = crud.get_by_id(emr_integration_id)
|
||||
if not db_emr_integration:
|
||||
raise HTTPException(
|
||||
status_code=status.HTTP_404_NOT_FOUND,
|
||||
detail=f"EMRIntegration with id { emr_integration_id} not found"
|
||||
)
|
||||
return crud.update(emr_integration_id, emr_integration_in)
|
||||
|
||||
@router.delete("/{ emr_integration_id }", status_code=status.HTTP_204_NO_CONTENT)
|
||||
async def delete_emr_integration(
|
||||
emr_integration_id: UUID,
|
||||
crud: EMRIntegrationCRUD = Depends(get_crud),
|
||||
):
|
||||
"""
|
||||
Delete a emrintegration.
|
||||
|
||||
- **emr_integration_id**: The UUID of the emrintegration to delete
|
||||
"""
|
||||
db_emr_integration = crud.get_by_id(emr_integration_id)
|
||||
if not db_emr_integration:
|
||||
raise HTTPException(
|
||||
status_code=status.HTTP_404_NOT_FOUND,
|
||||
detail=f"EMRIntegration with id { emr_integration_id} not found"
|
||||
)
|
||||
crud.delete(emr_integration_id)
|
||||
return None
|
||||
@ -35,7 +35,7 @@ async def list_emr_integrations(
|
||||
- **skip**: Number of records to skip (for pagination)
|
||||
- **limit**: Maximum number of records to return
|
||||
"""
|
||||
items, total = crud.get_all(skip=skip, limit=limit)
|
||||
items, total = await crud.get_all(skip=skip, limit=limit)
|
||||
|
||||
return EMRIntegrationListResponse(
|
||||
items=items,
|
||||
@ -55,7 +55,7 @@ async def get_emr_integration(
|
||||
|
||||
- **emr_integration_id**: The UUID of the emrintegration
|
||||
"""
|
||||
db_emr_integration = crud.get_by_id(emr_integration_id)
|
||||
db_emr_integration = await crud.get_by_id(emr_integration_id)
|
||||
if not db_emr_integration:
|
||||
raise HTTPException(
|
||||
status_code=status.HTTP_404_NOT_FOUND,
|
||||
@ -73,7 +73,7 @@ async def create_emr_integration(
|
||||
|
||||
- **emr_integration_in**: The emrintegration data to create
|
||||
"""
|
||||
return crud.create(emr_integration_in)
|
||||
return await crud.create(emr_integration_in)
|
||||
|
||||
@router.put("/{ emr_integration_id }", response_model=EMRIntegrationResponse)
|
||||
async def update_emr_integration(
|
||||
@ -87,13 +87,13 @@ async def update_emr_integration(
|
||||
- **emr_integration_id**: The UUID of the emrintegration to update
|
||||
- **emr_integration_in**: The updated emrintegration data
|
||||
"""
|
||||
db_emr_integration = crud.get_by_id(emr_integration_id)
|
||||
db_emr_integration = await crud.get_by_id(emr_integration_id)
|
||||
if not db_emr_integration:
|
||||
raise HTTPException(
|
||||
status_code=status.HTTP_404_NOT_FOUND,
|
||||
detail=f"EMRIntegration with id { emr_integration_id} not found"
|
||||
)
|
||||
return crud.update(emr_integration_id, emr_integration_in)
|
||||
return await crud.update(emr_integration_id, emr_integration_in)
|
||||
|
||||
@router.delete("/{ emr_integration_id }", status_code=status.HTTP_204_NO_CONTENT)
|
||||
async def delete_emr_integration(
|
||||
@ -105,11 +105,11 @@ async def delete_emr_integration(
|
||||
|
||||
- **emr_integration_id**: The UUID of the emrintegration to delete
|
||||
"""
|
||||
db_emr_integration = crud.get_by_id(emr_integration_id)
|
||||
db_emr_integration = await crud.get_by_id(emr_integration_id)
|
||||
if not db_emr_integration:
|
||||
raise HTTPException(
|
||||
status_code=status.HTTP_404_NOT_FOUND,
|
||||
detail=f"EMRIntegration with id { emr_integration_id} not found"
|
||||
)
|
||||
crud.delete(emr_integration_id)
|
||||
await crud.delete(emr_integration_id)
|
||||
return None
|
||||
|
||||
@ -1,115 +0,0 @@
|
||||
"""
|
||||
ClinicalEntity API Router
|
||||
Enterprise-grade FastAPI router with full CRUD operations
|
||||
Architecture: Routers → Services/CRUD → SQLAlchemy Models + Pydantic Schemas
|
||||
"""
|
||||
from typing import List, Optional
|
||||
from fastapi import APIRouter, Depends, HTTPException, Query, status
|
||||
from sqlalchemy.orm import Session
|
||||
from uuid import UUID
|
||||
|
||||
from src.config.database import get_db
|
||||
from src.services.clinical_entity_service import ClinicalEntityCRUD
|
||||
from src.validation.clinical_entity_schemas import (
|
||||
ClinicalEntityCreate,
|
||||
ClinicalEntityUpdate,
|
||||
ClinicalEntityResponse,
|
||||
ClinicalEntityListResponse,
|
||||
)
|
||||
|
||||
router = APIRouter(prefix="/clinicalentities", tags=["ClinicalEntity"])
|
||||
|
||||
def get_crud(db: Session = Depends(get_db)) -> ClinicalEntityCRUD:
|
||||
"""Dependency injection for ClinicalEntityCRUD"""
|
||||
return ClinicalEntityCRUD(db)
|
||||
|
||||
@router.get("/", response_model=ClinicalEntityListResponse)
|
||||
async def list_clinical_entities(
|
||||
skip: int = Query(0, ge=0, description="Number of records to skip"),
|
||||
limit: int = Query(100, ge=1, le=1000, description="Maximum records to return"),
|
||||
crud: ClinicalEntityCRUD = Depends(get_crud),
|
||||
):
|
||||
"""
|
||||
List all clinicalentities with pagination and filtering.
|
||||
|
||||
- **skip**: Number of records to skip (for pagination)
|
||||
- **limit**: Maximum number of records to return
|
||||
"""
|
||||
items, total = crud.get_all(skip=skip, limit=limit)
|
||||
|
||||
return ClinicalEntityListResponse(
|
||||
items=items,
|
||||
total=total,
|
||||
skip=skip,
|
||||
limit=limit,
|
||||
has_more=skip + limit < total
|
||||
)
|
||||
|
||||
@router.get("/{ clinical_entity_id }", response_model=ClinicalEntityResponse)
|
||||
async def get_clinical_entity(
|
||||
clinical_entity_id: UUID,
|
||||
crud: ClinicalEntityCRUD = Depends(get_crud),
|
||||
):
|
||||
"""
|
||||
Get a specific clinicalentity by ID.
|
||||
|
||||
- **clinical_entity_id**: The UUID of the clinicalentity
|
||||
"""
|
||||
db_clinical_entity = crud.get_by_id(clinical_entity_id)
|
||||
if not db_clinical_entity:
|
||||
raise HTTPException(
|
||||
status_code=status.HTTP_404_NOT_FOUND,
|
||||
detail=f"ClinicalEntity with id { clinical_entity_id} not found"
|
||||
)
|
||||
return db_clinical_entity
|
||||
|
||||
@router.post("/", response_model=ClinicalEntityResponse, status_code=status.HTTP_201_CREATED)
|
||||
async def create_clinical_entity(
|
||||
clinical_entity_in: ClinicalEntityCreate,
|
||||
crud: ClinicalEntityCRUD = Depends(get_crud),
|
||||
):
|
||||
"""
|
||||
Create a new clinicalentity.
|
||||
|
||||
- **clinical_entity_in**: The clinicalentity data to create
|
||||
"""
|
||||
return crud.create(clinical_entity_in)
|
||||
|
||||
@router.put("/{ clinical_entity_id }", response_model=ClinicalEntityResponse)
|
||||
async def update_clinical_entity(
|
||||
clinical_entity_id: UUID,
|
||||
clinical_entity_in: ClinicalEntityUpdate,
|
||||
crud: ClinicalEntityCRUD = Depends(get_crud),
|
||||
):
|
||||
"""
|
||||
Update an existing clinicalentity.
|
||||
|
||||
- **clinical_entity_id**: The UUID of the clinicalentity to update
|
||||
- **clinical_entity_in**: The updated clinicalentity data
|
||||
"""
|
||||
db_clinical_entity = crud.get_by_id(clinical_entity_id)
|
||||
if not db_clinical_entity:
|
||||
raise HTTPException(
|
||||
status_code=status.HTTP_404_NOT_FOUND,
|
||||
detail=f"ClinicalEntity with id { clinical_entity_id} not found"
|
||||
)
|
||||
return crud.update(clinical_entity_id, clinical_entity_in)
|
||||
|
||||
@router.delete("/{ clinical_entity_id }", status_code=status.HTTP_204_NO_CONTENT)
|
||||
async def delete_clinical_entity(
|
||||
clinical_entity_id: UUID,
|
||||
crud: ClinicalEntityCRUD = Depends(get_crud),
|
||||
):
|
||||
"""
|
||||
Delete a clinicalentity.
|
||||
|
||||
- **clinical_entity_id**: The UUID of the clinicalentity to delete
|
||||
"""
|
||||
db_clinical_entity = crud.get_by_id(clinical_entity_id)
|
||||
if not db_clinical_entity:
|
||||
raise HTTPException(
|
||||
status_code=status.HTTP_404_NOT_FOUND,
|
||||
detail=f"ClinicalEntity with id { clinical_entity_id} not found"
|
||||
)
|
||||
crud.delete(clinical_entity_id)
|
||||
return None
|
||||
@ -1,115 +0,0 @@
|
||||
"""
|
||||
ClaimReview API Router
|
||||
Enterprise-grade FastAPI router with full CRUD operations
|
||||
Architecture: Routers → Services/CRUD → SQLAlchemy Models + Pydantic Schemas
|
||||
"""
|
||||
from typing import List, Optional
|
||||
from fastapi import APIRouter, Depends, HTTPException, Query, status
|
||||
from sqlalchemy.orm import Session
|
||||
from uuid import UUID
|
||||
|
||||
from src.config.database import get_db
|
||||
from src.services.claim_review_service import ClaimReviewCRUD
|
||||
from src.validation.claim_review_schemas import (
|
||||
ClaimReviewCreate,
|
||||
ClaimReviewUpdate,
|
||||
ClaimReviewResponse,
|
||||
ClaimReviewListResponse,
|
||||
)
|
||||
|
||||
router = APIRouter(prefix="/claimreviews", tags=["ClaimReview"])
|
||||
|
||||
def get_crud(db: Session = Depends(get_db)) -> ClaimReviewCRUD:
|
||||
"""Dependency injection for ClaimReviewCRUD"""
|
||||
return ClaimReviewCRUD(db)
|
||||
|
||||
@router.get("/", response_model=ClaimReviewListResponse)
|
||||
async def list_claim_reviews(
|
||||
skip: int = Query(0, ge=0, description="Number of records to skip"),
|
||||
limit: int = Query(100, ge=1, le=1000, description="Maximum records to return"),
|
||||
crud: ClaimReviewCRUD = Depends(get_crud),
|
||||
):
|
||||
"""
|
||||
List all claimreviews with pagination and filtering.
|
||||
|
||||
- **skip**: Number of records to skip (for pagination)
|
||||
- **limit**: Maximum number of records to return
|
||||
"""
|
||||
items, total = crud.get_all(skip=skip, limit=limit)
|
||||
|
||||
return ClaimReviewListResponse(
|
||||
items=items,
|
||||
total=total,
|
||||
skip=skip,
|
||||
limit=limit,
|
||||
has_more=skip + limit < total
|
||||
)
|
||||
|
||||
@router.get("/{ claim_review_id }", response_model=ClaimReviewResponse)
|
||||
async def get_claim_review(
|
||||
claim_review_id: UUID,
|
||||
crud: ClaimReviewCRUD = Depends(get_crud),
|
||||
):
|
||||
"""
|
||||
Get a specific claimreview by ID.
|
||||
|
||||
- **claim_review_id**: The UUID of the claimreview
|
||||
"""
|
||||
db_claim_review = crud.get_by_id(claim_review_id)
|
||||
if not db_claim_review:
|
||||
raise HTTPException(
|
||||
status_code=status.HTTP_404_NOT_FOUND,
|
||||
detail=f"ClaimReview with id { claim_review_id} not found"
|
||||
)
|
||||
return db_claim_review
|
||||
|
||||
@router.post("/", response_model=ClaimReviewResponse, status_code=status.HTTP_201_CREATED)
|
||||
async def create_claim_review(
|
||||
claim_review_in: ClaimReviewCreate,
|
||||
crud: ClaimReviewCRUD = Depends(get_crud),
|
||||
):
|
||||
"""
|
||||
Create a new claimreview.
|
||||
|
||||
- **claim_review_in**: The claimreview data to create
|
||||
"""
|
||||
return crud.create(claim_review_in)
|
||||
|
||||
@router.put("/{ claim_review_id }", response_model=ClaimReviewResponse)
|
||||
async def update_claim_review(
|
||||
claim_review_id: UUID,
|
||||
claim_review_in: ClaimReviewUpdate,
|
||||
crud: ClaimReviewCRUD = Depends(get_crud),
|
||||
):
|
||||
"""
|
||||
Update an existing claimreview.
|
||||
|
||||
- **claim_review_id**: The UUID of the claimreview to update
|
||||
- **claim_review_in**: The updated claimreview data
|
||||
"""
|
||||
db_claim_review = crud.get_by_id(claim_review_id)
|
||||
if not db_claim_review:
|
||||
raise HTTPException(
|
||||
status_code=status.HTTP_404_NOT_FOUND,
|
||||
detail=f"ClaimReview with id { claim_review_id} not found"
|
||||
)
|
||||
return crud.update(claim_review_id, claim_review_in)
|
||||
|
||||
@router.delete("/{ claim_review_id }", status_code=status.HTTP_204_NO_CONTENT)
|
||||
async def delete_claim_review(
|
||||
claim_review_id: UUID,
|
||||
crud: ClaimReviewCRUD = Depends(get_crud),
|
||||
):
|
||||
"""
|
||||
Delete a claimreview.
|
||||
|
||||
- **claim_review_id**: The UUID of the claimreview to delete
|
||||
"""
|
||||
db_claim_review = crud.get_by_id(claim_review_id)
|
||||
if not db_claim_review:
|
||||
raise HTTPException(
|
||||
status_code=status.HTTP_404_NOT_FOUND,
|
||||
detail=f"ClaimReview with id { claim_review_id} not found"
|
||||
)
|
||||
crud.delete(claim_review_id)
|
||||
return None
|
||||
@ -35,7 +35,7 @@ async def list_icd10_codes(
|
||||
- **skip**: Number of records to skip (for pagination)
|
||||
- **limit**: Maximum number of records to return
|
||||
"""
|
||||
items, total = crud.get_all(skip=skip, limit=limit)
|
||||
items, total = await crud.get_all(skip=skip, limit=limit)
|
||||
|
||||
return ICD10CodeListResponse(
|
||||
items=items,
|
||||
@ -55,7 +55,7 @@ async def get_icd10_code(
|
||||
|
||||
- **icd10_code_id**: The UUID of the icd10code
|
||||
"""
|
||||
db_icd10_code = crud.get_by_id(icd10_code_id)
|
||||
db_icd10_code = await crud.get_by_id(icd10_code_id)
|
||||
if not db_icd10_code:
|
||||
raise HTTPException(
|
||||
status_code=status.HTTP_404_NOT_FOUND,
|
||||
@ -73,7 +73,7 @@ async def create_icd10_code(
|
||||
|
||||
- **icd10_code_in**: The icd10code data to create
|
||||
"""
|
||||
return crud.create(icd10_code_in)
|
||||
return await crud.create(icd10_code_in)
|
||||
|
||||
@router.put("/{ icd10_code_id }", response_model=ICD10CodeResponse)
|
||||
async def update_icd10_code(
|
||||
@ -87,13 +87,13 @@ async def update_icd10_code(
|
||||
- **icd10_code_id**: The UUID of the icd10code to update
|
||||
- **icd10_code_in**: The updated icd10code data
|
||||
"""
|
||||
db_icd10_code = crud.get_by_id(icd10_code_id)
|
||||
db_icd10_code = await crud.get_by_id(icd10_code_id)
|
||||
if not db_icd10_code:
|
||||
raise HTTPException(
|
||||
status_code=status.HTTP_404_NOT_FOUND,
|
||||
detail=f"ICD10Code with id { icd10_code_id} not found"
|
||||
)
|
||||
return crud.update(icd10_code_id, icd10_code_in)
|
||||
return await crud.update(icd10_code_id, icd10_code_in)
|
||||
|
||||
@router.delete("/{ icd10_code_id }", status_code=status.HTTP_204_NO_CONTENT)
|
||||
async def delete_icd10_code(
|
||||
@ -105,11 +105,11 @@ async def delete_icd10_code(
|
||||
|
||||
- **icd10_code_id**: The UUID of the icd10code to delete
|
||||
"""
|
||||
db_icd10_code = crud.get_by_id(icd10_code_id)
|
||||
db_icd10_code = await crud.get_by_id(icd10_code_id)
|
||||
if not db_icd10_code:
|
||||
raise HTTPException(
|
||||
status_code=status.HTTP_404_NOT_FOUND,
|
||||
detail=f"ICD10Code with id { icd10_code_id} not found"
|
||||
)
|
||||
crud.delete(icd10_code_id)
|
||||
await crud.delete(icd10_code_id)
|
||||
return None
|
||||
|
||||
@ -35,7 +35,7 @@ async def list_lc_ds(
|
||||
- **skip**: Number of records to skip (for pagination)
|
||||
- **limit**: Maximum number of records to return
|
||||
"""
|
||||
items, total = crud.get_all(skip=skip, limit=limit)
|
||||
items, total = await crud.get_all(skip=skip, limit=limit)
|
||||
|
||||
return LCDListResponse(
|
||||
items=items,
|
||||
@ -55,7 +55,7 @@ async def get_lcd(
|
||||
|
||||
- **lcd_id**: The UUID of the lcd
|
||||
"""
|
||||
db_lcd = crud.get_by_id(lcd_id)
|
||||
db_lcd = await crud.get_by_id(lcd_id)
|
||||
if not db_lcd:
|
||||
raise HTTPException(
|
||||
status_code=status.HTTP_404_NOT_FOUND,
|
||||
@ -73,7 +73,7 @@ async def create_lcd(
|
||||
|
||||
- **lcd_in**: The lcd data to create
|
||||
"""
|
||||
return crud.create(lcd_in)
|
||||
return await crud.create(lcd_in)
|
||||
|
||||
@router.put("/{ lcd_id }", response_model=LCDResponse)
|
||||
async def update_lcd(
|
||||
@ -87,13 +87,13 @@ async def update_lcd(
|
||||
- **lcd_id**: The UUID of the lcd to update
|
||||
- **lcd_in**: The updated lcd data
|
||||
"""
|
||||
db_lcd = crud.get_by_id(lcd_id)
|
||||
db_lcd = await crud.get_by_id(lcd_id)
|
||||
if not db_lcd:
|
||||
raise HTTPException(
|
||||
status_code=status.HTTP_404_NOT_FOUND,
|
||||
detail=f"LCD with id { lcd_id} not found"
|
||||
)
|
||||
return crud.update(lcd_id, lcd_in)
|
||||
return await crud.update(lcd_id, lcd_in)
|
||||
|
||||
@router.delete("/{ lcd_id }", status_code=status.HTTP_204_NO_CONTENT)
|
||||
async def delete_lcd(
|
||||
@ -105,11 +105,11 @@ async def delete_lcd(
|
||||
|
||||
- **lcd_id**: The UUID of the lcd to delete
|
||||
"""
|
||||
db_lcd = crud.get_by_id(lcd_id)
|
||||
db_lcd = await crud.get_by_id(lcd_id)
|
||||
if not db_lcd:
|
||||
raise HTTPException(
|
||||
status_code=status.HTTP_404_NOT_FOUND,
|
||||
detail=f"LCD with id { lcd_id} not found"
|
||||
)
|
||||
crud.delete(lcd_id)
|
||||
await crud.delete(lcd_id)
|
||||
return None
|
||||
|
||||
@ -35,7 +35,7 @@ async def list_ncci_edits(
|
||||
- **skip**: Number of records to skip (for pagination)
|
||||
- **limit**: Maximum number of records to return
|
||||
"""
|
||||
items, total = crud.get_all(skip=skip, limit=limit)
|
||||
items, total = await crud.get_all(skip=skip, limit=limit)
|
||||
|
||||
return NCCIEditListResponse(
|
||||
items=items,
|
||||
@ -55,7 +55,7 @@ async def get_ncci_edit(
|
||||
|
||||
- **ncci_edit_id**: The UUID of the ncciedit
|
||||
"""
|
||||
db_ncci_edit = crud.get_by_id(ncci_edit_id)
|
||||
db_ncci_edit = await crud.get_by_id(ncci_edit_id)
|
||||
if not db_ncci_edit:
|
||||
raise HTTPException(
|
||||
status_code=status.HTTP_404_NOT_FOUND,
|
||||
@ -73,7 +73,7 @@ async def create_ncci_edit(
|
||||
|
||||
- **ncci_edit_in**: The ncciedit data to create
|
||||
"""
|
||||
return crud.create(ncci_edit_in)
|
||||
return await crud.create(ncci_edit_in)
|
||||
|
||||
@router.put("/{ ncci_edit_id }", response_model=NCCIEditResponse)
|
||||
async def update_ncci_edit(
|
||||
@ -87,13 +87,13 @@ async def update_ncci_edit(
|
||||
- **ncci_edit_id**: The UUID of the ncciedit to update
|
||||
- **ncci_edit_in**: The updated ncciedit data
|
||||
"""
|
||||
db_ncci_edit = crud.get_by_id(ncci_edit_id)
|
||||
db_ncci_edit = await crud.get_by_id(ncci_edit_id)
|
||||
if not db_ncci_edit:
|
||||
raise HTTPException(
|
||||
status_code=status.HTTP_404_NOT_FOUND,
|
||||
detail=f"NCCIEdit with id { ncci_edit_id} not found"
|
||||
)
|
||||
return crud.update(ncci_edit_id, ncci_edit_in)
|
||||
return await crud.update(ncci_edit_id, ncci_edit_in)
|
||||
|
||||
@router.delete("/{ ncci_edit_id }", status_code=status.HTTP_204_NO_CONTENT)
|
||||
async def delete_ncci_edit(
|
||||
@ -105,11 +105,11 @@ async def delete_ncci_edit(
|
||||
|
||||
- **ncci_edit_id**: The UUID of the ncciedit to delete
|
||||
"""
|
||||
db_ncci_edit = crud.get_by_id(ncci_edit_id)
|
||||
db_ncci_edit = await crud.get_by_id(ncci_edit_id)
|
||||
if not db_ncci_edit:
|
||||
raise HTTPException(
|
||||
status_code=status.HTTP_404_NOT_FOUND,
|
||||
detail=f"NCCIEdit with id { ncci_edit_id} not found"
|
||||
)
|
||||
crud.delete(ncci_edit_id)
|
||||
await crud.delete(ncci_edit_id)
|
||||
return None
|
||||
|
||||
@ -35,7 +35,7 @@ async def list_nc_ds(
|
||||
- **skip**: Number of records to skip (for pagination)
|
||||
- **limit**: Maximum number of records to return
|
||||
"""
|
||||
items, total = crud.get_all(skip=skip, limit=limit)
|
||||
items, total = await crud.get_all(skip=skip, limit=limit)
|
||||
|
||||
return NCDListResponse(
|
||||
items=items,
|
||||
@ -55,7 +55,7 @@ async def get_ncd(
|
||||
|
||||
- **ncd_id**: The UUID of the ncd
|
||||
"""
|
||||
db_ncd = crud.get_by_id(ncd_id)
|
||||
db_ncd = await crud.get_by_id(ncd_id)
|
||||
if not db_ncd:
|
||||
raise HTTPException(
|
||||
status_code=status.HTTP_404_NOT_FOUND,
|
||||
@ -73,7 +73,7 @@ async def create_ncd(
|
||||
|
||||
- **ncd_in**: The ncd data to create
|
||||
"""
|
||||
return crud.create(ncd_in)
|
||||
return await crud.create(ncd_in)
|
||||
|
||||
@router.put("/{ ncd_id }", response_model=NCDResponse)
|
||||
async def update_ncd(
|
||||
@ -87,13 +87,13 @@ async def update_ncd(
|
||||
- **ncd_id**: The UUID of the ncd to update
|
||||
- **ncd_in**: The updated ncd data
|
||||
"""
|
||||
db_ncd = crud.get_by_id(ncd_id)
|
||||
db_ncd = await crud.get_by_id(ncd_id)
|
||||
if not db_ncd:
|
||||
raise HTTPException(
|
||||
status_code=status.HTTP_404_NOT_FOUND,
|
||||
detail=f"NCD with id { ncd_id} not found"
|
||||
)
|
||||
return crud.update(ncd_id, ncd_in)
|
||||
return await crud.update(ncd_id, ncd_in)
|
||||
|
||||
@router.delete("/{ ncd_id }", status_code=status.HTTP_204_NO_CONTENT)
|
||||
async def delete_ncd(
|
||||
@ -105,11 +105,11 @@ async def delete_ncd(
|
||||
|
||||
- **ncd_id**: The UUID of the ncd to delete
|
||||
"""
|
||||
db_ncd = crud.get_by_id(ncd_id)
|
||||
db_ncd = await crud.get_by_id(ncd_id)
|
||||
if not db_ncd:
|
||||
raise HTTPException(
|
||||
status_code=status.HTTP_404_NOT_FOUND,
|
||||
detail=f"NCD with id { ncd_id} not found"
|
||||
)
|
||||
crud.delete(ncd_id)
|
||||
await crud.delete(ncd_id)
|
||||
return None
|
||||
|
||||
@ -1,115 +0,0 @@
|
||||
"""
|
||||
Patient API Router
|
||||
Enterprise-grade FastAPI router with full CRUD operations
|
||||
Architecture: Routers → Services/CRUD → SQLAlchemy Models + Pydantic Schemas
|
||||
"""
|
||||
from typing import List, Optional
|
||||
from fastapi import APIRouter, Depends, HTTPException, Query, status
|
||||
from sqlalchemy.orm import Session
|
||||
from uuid import UUID
|
||||
|
||||
from src.config.database import get_db
|
||||
from src.services.patient_service import PatientCRUD
|
||||
from src.validation.patient_schemas import (
|
||||
PatientCreate,
|
||||
PatientUpdate,
|
||||
PatientResponse,
|
||||
PatientListResponse,
|
||||
)
|
||||
|
||||
router = APIRouter(prefix="/patients", tags=["Patient"])
|
||||
|
||||
def get_crud(db: Session = Depends(get_db)) -> PatientCRUD:
|
||||
"""Dependency injection for PatientCRUD"""
|
||||
return PatientCRUD(db)
|
||||
|
||||
@router.get("/", response_model=PatientListResponse)
|
||||
async def list_patients(
|
||||
skip: int = Query(0, ge=0, description="Number of records to skip"),
|
||||
limit: int = Query(100, ge=1, le=1000, description="Maximum records to return"),
|
||||
crud: PatientCRUD = Depends(get_crud),
|
||||
):
|
||||
"""
|
||||
List all patients with pagination and filtering.
|
||||
|
||||
- **skip**: Number of records to skip (for pagination)
|
||||
- **limit**: Maximum number of records to return
|
||||
"""
|
||||
items, total = crud.get_all(skip=skip, limit=limit)
|
||||
|
||||
return PatientListResponse(
|
||||
items=items,
|
||||
total=total,
|
||||
skip=skip,
|
||||
limit=limit,
|
||||
has_more=skip + limit < total
|
||||
)
|
||||
|
||||
@router.get("/{ patient_id }", response_model=PatientResponse)
|
||||
async def get_patient(
|
||||
patient_id: UUID,
|
||||
crud: PatientCRUD = Depends(get_crud),
|
||||
):
|
||||
"""
|
||||
Get a specific patient by ID.
|
||||
|
||||
- **patient_id**: The UUID of the patient
|
||||
"""
|
||||
db_patient = crud.get_by_id(patient_id)
|
||||
if not db_patient:
|
||||
raise HTTPException(
|
||||
status_code=status.HTTP_404_NOT_FOUND,
|
||||
detail=f"Patient with id { patient_id} not found"
|
||||
)
|
||||
return db_patient
|
||||
|
||||
@router.post("/", response_model=PatientResponse, status_code=status.HTTP_201_CREATED)
|
||||
async def create_patient(
|
||||
patient_in: PatientCreate,
|
||||
crud: PatientCRUD = Depends(get_crud),
|
||||
):
|
||||
"""
|
||||
Create a new patient.
|
||||
|
||||
- **patient_in**: The patient data to create
|
||||
"""
|
||||
return crud.create(patient_in)
|
||||
|
||||
@router.put("/{ patient_id }", response_model=PatientResponse)
|
||||
async def update_patient(
|
||||
patient_id: UUID,
|
||||
patient_in: PatientUpdate,
|
||||
crud: PatientCRUD = Depends(get_crud),
|
||||
):
|
||||
"""
|
||||
Update an existing patient.
|
||||
|
||||
- **patient_id**: The UUID of the patient to update
|
||||
- **patient_in**: The updated patient data
|
||||
"""
|
||||
db_patient = crud.get_by_id(patient_id)
|
||||
if not db_patient:
|
||||
raise HTTPException(
|
||||
status_code=status.HTTP_404_NOT_FOUND,
|
||||
detail=f"Patient with id { patient_id} not found"
|
||||
)
|
||||
return crud.update(patient_id, patient_in)
|
||||
|
||||
@router.delete("/{ patient_id }", status_code=status.HTTP_204_NO_CONTENT)
|
||||
async def delete_patient(
|
||||
patient_id: UUID,
|
||||
crud: PatientCRUD = Depends(get_crud),
|
||||
):
|
||||
"""
|
||||
Delete a patient.
|
||||
|
||||
- **patient_id**: The UUID of the patient to delete
|
||||
"""
|
||||
db_patient = crud.get_by_id(patient_id)
|
||||
if not db_patient:
|
||||
raise HTTPException(
|
||||
status_code=status.HTTP_404_NOT_FOUND,
|
||||
detail=f"Patient with id { patient_id} not found"
|
||||
)
|
||||
crud.delete(patient_id)
|
||||
return None
|
||||
@ -35,7 +35,7 @@ async def list_patients(
|
||||
- **skip**: Number of records to skip (for pagination)
|
||||
- **limit**: Maximum number of records to return
|
||||
"""
|
||||
items, total = crud.get_all(skip=skip, limit=limit)
|
||||
items, total = await crud.get_all(skip=skip, limit=limit)
|
||||
|
||||
return PatientListResponse(
|
||||
items=items,
|
||||
@ -55,7 +55,7 @@ async def get_patient(
|
||||
|
||||
- **patient_id**: The UUID of the patient
|
||||
"""
|
||||
db_patient = crud.get_by_id(patient_id)
|
||||
db_patient = await crud.get_by_id(patient_id)
|
||||
if not db_patient:
|
||||
raise HTTPException(
|
||||
status_code=status.HTTP_404_NOT_FOUND,
|
||||
@ -73,7 +73,7 @@ async def create_patient(
|
||||
|
||||
- **patient_in**: The patient data to create
|
||||
"""
|
||||
return crud.create(patient_in)
|
||||
return await crud.create(patient_in)
|
||||
|
||||
@router.put("/{ patient_id }", response_model=PatientResponse)
|
||||
async def update_patient(
|
||||
@ -87,13 +87,13 @@ async def update_patient(
|
||||
- **patient_id**: The UUID of the patient to update
|
||||
- **patient_in**: The updated patient data
|
||||
"""
|
||||
db_patient = crud.get_by_id(patient_id)
|
||||
db_patient = await crud.get_by_id(patient_id)
|
||||
if not db_patient:
|
||||
raise HTTPException(
|
||||
status_code=status.HTTP_404_NOT_FOUND,
|
||||
detail=f"Patient with id { patient_id} not found"
|
||||
)
|
||||
return crud.update(patient_id, patient_in)
|
||||
return await crud.update(patient_id, patient_in)
|
||||
|
||||
@router.delete("/{ patient_id }", status_code=status.HTTP_204_NO_CONTENT)
|
||||
async def delete_patient(
|
||||
@ -105,11 +105,11 @@ async def delete_patient(
|
||||
|
||||
- **patient_id**: The UUID of the patient to delete
|
||||
"""
|
||||
db_patient = crud.get_by_id(patient_id)
|
||||
db_patient = await crud.get_by_id(patient_id)
|
||||
if not db_patient:
|
||||
raise HTTPException(
|
||||
status_code=status.HTTP_404_NOT_FOUND,
|
||||
detail=f"Patient with id { patient_id} not found"
|
||||
)
|
||||
crud.delete(patient_id)
|
||||
await crud.delete(patient_id)
|
||||
return None
|
||||
|
||||
@ -35,7 +35,7 @@ async def list_payers(
|
||||
- **skip**: Number of records to skip (for pagination)
|
||||
- **limit**: Maximum number of records to return
|
||||
"""
|
||||
items, total = crud.get_all(skip=skip, limit=limit)
|
||||
items, total = await crud.get_all(skip=skip, limit=limit)
|
||||
|
||||
return PayerListResponse(
|
||||
items=items,
|
||||
@ -55,7 +55,7 @@ async def get_payer(
|
||||
|
||||
- **payer_id**: The UUID of the payer
|
||||
"""
|
||||
db_payer = crud.get_by_id(payer_id)
|
||||
db_payer = await crud.get_by_id(payer_id)
|
||||
if not db_payer:
|
||||
raise HTTPException(
|
||||
status_code=status.HTTP_404_NOT_FOUND,
|
||||
@ -73,7 +73,7 @@ async def create_payer(
|
||||
|
||||
- **payer_in**: The payer data to create
|
||||
"""
|
||||
return crud.create(payer_in)
|
||||
return await crud.create(payer_in)
|
||||
|
||||
@router.put("/{ payer_id }", response_model=PayerResponse)
|
||||
async def update_payer(
|
||||
@ -87,13 +87,13 @@ async def update_payer(
|
||||
- **payer_id**: The UUID of the payer to update
|
||||
- **payer_in**: The updated payer data
|
||||
"""
|
||||
db_payer = crud.get_by_id(payer_id)
|
||||
db_payer = await crud.get_by_id(payer_id)
|
||||
if not db_payer:
|
||||
raise HTTPException(
|
||||
status_code=status.HTTP_404_NOT_FOUND,
|
||||
detail=f"Payer with id { payer_id} not found"
|
||||
)
|
||||
return crud.update(payer_id, payer_in)
|
||||
return await crud.update(payer_id, payer_in)
|
||||
|
||||
@router.delete("/{ payer_id }", status_code=status.HTTP_204_NO_CONTENT)
|
||||
async def delete_payer(
|
||||
@ -105,11 +105,11 @@ async def delete_payer(
|
||||
|
||||
- **payer_id**: The UUID of the payer to delete
|
||||
"""
|
||||
db_payer = crud.get_by_id(payer_id)
|
||||
db_payer = await crud.get_by_id(payer_id)
|
||||
if not db_payer:
|
||||
raise HTTPException(
|
||||
status_code=status.HTTP_404_NOT_FOUND,
|
||||
detail=f"Payer with id { payer_id} not found"
|
||||
)
|
||||
crud.delete(payer_id)
|
||||
await crud.delete(payer_id)
|
||||
return None
|
||||
|
||||
@ -35,7 +35,7 @@ async def list_payer_rules(
|
||||
- **skip**: Number of records to skip (for pagination)
|
||||
- **limit**: Maximum number of records to return
|
||||
"""
|
||||
items, total = crud.get_all(skip=skip, limit=limit)
|
||||
items, total = await crud.get_all(skip=skip, limit=limit)
|
||||
|
||||
return PayerRuleListResponse(
|
||||
items=items,
|
||||
@ -55,7 +55,7 @@ async def get_payer_rule(
|
||||
|
||||
- **payer_rule_id**: The UUID of the payerrule
|
||||
"""
|
||||
db_payer_rule = crud.get_by_id(payer_rule_id)
|
||||
db_payer_rule = await crud.get_by_id(payer_rule_id)
|
||||
if not db_payer_rule:
|
||||
raise HTTPException(
|
||||
status_code=status.HTTP_404_NOT_FOUND,
|
||||
@ -73,7 +73,7 @@ async def create_payer_rule(
|
||||
|
||||
- **payer_rule_in**: The payerrule data to create
|
||||
"""
|
||||
return crud.create(payer_rule_in)
|
||||
return await crud.create(payer_rule_in)
|
||||
|
||||
@router.put("/{ payer_rule_id }", response_model=PayerRuleResponse)
|
||||
async def update_payer_rule(
|
||||
@ -87,13 +87,13 @@ async def update_payer_rule(
|
||||
- **payer_rule_id**: The UUID of the payerrule to update
|
||||
- **payer_rule_in**: The updated payerrule data
|
||||
"""
|
||||
db_payer_rule = crud.get_by_id(payer_rule_id)
|
||||
db_payer_rule = await crud.get_by_id(payer_rule_id)
|
||||
if not db_payer_rule:
|
||||
raise HTTPException(
|
||||
status_code=status.HTTP_404_NOT_FOUND,
|
||||
detail=f"PayerRule with id { payer_rule_id} not found"
|
||||
)
|
||||
return crud.update(payer_rule_id, payer_rule_in)
|
||||
return await crud.update(payer_rule_id, payer_rule_in)
|
||||
|
||||
@router.delete("/{ payer_rule_id }", status_code=status.HTTP_204_NO_CONTENT)
|
||||
async def delete_payer_rule(
|
||||
@ -105,11 +105,11 @@ async def delete_payer_rule(
|
||||
|
||||
- **payer_rule_id**: The UUID of the payerrule to delete
|
||||
"""
|
||||
db_payer_rule = crud.get_by_id(payer_rule_id)
|
||||
db_payer_rule = await crud.get_by_id(payer_rule_id)
|
||||
if not db_payer_rule:
|
||||
raise HTTPException(
|
||||
status_code=status.HTTP_404_NOT_FOUND,
|
||||
detail=f"PayerRule with id { payer_rule_id} not found"
|
||||
)
|
||||
crud.delete(payer_rule_id)
|
||||
await crud.delete(payer_rule_id)
|
||||
return None
|
||||
|
||||
@ -1,115 +0,0 @@
|
||||
"""
|
||||
PayerRule API Router
|
||||
Enterprise-grade FastAPI router with full CRUD operations
|
||||
Architecture: Routers → Services/CRUD → SQLAlchemy Models + Pydantic Schemas
|
||||
"""
|
||||
from typing import List, Optional
|
||||
from fastapi import APIRouter, Depends, HTTPException, Query, status
|
||||
from sqlalchemy.orm import Session
|
||||
from uuid import UUID
|
||||
|
||||
from src.config.database import get_db
|
||||
from src.services.payer_rule_service import PayerRuleCRUD
|
||||
from src.validation.payer_rule_schemas import (
|
||||
PayerRuleCreate,
|
||||
PayerRuleUpdate,
|
||||
PayerRuleResponse,
|
||||
PayerRuleListResponse,
|
||||
)
|
||||
|
||||
router = APIRouter(prefix="/payerrules", tags=["PayerRule"])
|
||||
|
||||
def get_crud(db: Session = Depends(get_db)) -> PayerRuleCRUD:
|
||||
"""Dependency injection for PayerRuleCRUD"""
|
||||
return PayerRuleCRUD(db)
|
||||
|
||||
@router.get("/", response_model=PayerRuleListResponse)
|
||||
async def list_payer_rules(
|
||||
skip: int = Query(0, ge=0, description="Number of records to skip"),
|
||||
limit: int = Query(100, ge=1, le=1000, description="Maximum records to return"),
|
||||
crud: PayerRuleCRUD = Depends(get_crud),
|
||||
):
|
||||
"""
|
||||
List all payerrules with pagination and filtering.
|
||||
|
||||
- **skip**: Number of records to skip (for pagination)
|
||||
- **limit**: Maximum number of records to return
|
||||
"""
|
||||
items, total = crud.get_all(skip=skip, limit=limit)
|
||||
|
||||
return PayerRuleListResponse(
|
||||
items=items,
|
||||
total=total,
|
||||
skip=skip,
|
||||
limit=limit,
|
||||
has_more=skip + limit < total
|
||||
)
|
||||
|
||||
@router.get("/{ payer_rule_id }", response_model=PayerRuleResponse)
|
||||
async def get_payer_rule(
|
||||
payer_rule_id: UUID,
|
||||
crud: PayerRuleCRUD = Depends(get_crud),
|
||||
):
|
||||
"""
|
||||
Get a specific payerrule by ID.
|
||||
|
||||
- **payer_rule_id**: The UUID of the payerrule
|
||||
"""
|
||||
db_payer_rule = crud.get_by_id(payer_rule_id)
|
||||
if not db_payer_rule:
|
||||
raise HTTPException(
|
||||
status_code=status.HTTP_404_NOT_FOUND,
|
||||
detail=f"PayerRule with id { payer_rule_id} not found"
|
||||
)
|
||||
return db_payer_rule
|
||||
|
||||
@router.post("/", response_model=PayerRuleResponse, status_code=status.HTTP_201_CREATED)
|
||||
async def create_payer_rule(
|
||||
payer_rule_in: PayerRuleCreate,
|
||||
crud: PayerRuleCRUD = Depends(get_crud),
|
||||
):
|
||||
"""
|
||||
Create a new payerrule.
|
||||
|
||||
- **payer_rule_in**: The payerrule data to create
|
||||
"""
|
||||
return crud.create(payer_rule_in)
|
||||
|
||||
@router.put("/{ payer_rule_id }", response_model=PayerRuleResponse)
|
||||
async def update_payer_rule(
|
||||
payer_rule_id: UUID,
|
||||
payer_rule_in: PayerRuleUpdate,
|
||||
crud: PayerRuleCRUD = Depends(get_crud),
|
||||
):
|
||||
"""
|
||||
Update an existing payerrule.
|
||||
|
||||
- **payer_rule_id**: The UUID of the payerrule to update
|
||||
- **payer_rule_in**: The updated payerrule data
|
||||
"""
|
||||
db_payer_rule = crud.get_by_id(payer_rule_id)
|
||||
if not db_payer_rule:
|
||||
raise HTTPException(
|
||||
status_code=status.HTTP_404_NOT_FOUND,
|
||||
detail=f"PayerRule with id { payer_rule_id} not found"
|
||||
)
|
||||
return crud.update(payer_rule_id, payer_rule_in)
|
||||
|
||||
@router.delete("/{ payer_rule_id }", status_code=status.HTTP_204_NO_CONTENT)
|
||||
async def delete_payer_rule(
|
||||
payer_rule_id: UUID,
|
||||
crud: PayerRuleCRUD = Depends(get_crud),
|
||||
):
|
||||
"""
|
||||
Delete a payerrule.
|
||||
|
||||
- **payer_rule_id**: The UUID of the payerrule to delete
|
||||
"""
|
||||
db_payer_rule = crud.get_by_id(payer_rule_id)
|
||||
if not db_payer_rule:
|
||||
raise HTTPException(
|
||||
status_code=status.HTTP_404_NOT_FOUND,
|
||||
detail=f"PayerRule with id { payer_rule_id} not found"
|
||||
)
|
||||
crud.delete(payer_rule_id)
|
||||
return None
|
||||
@ -35,7 +35,7 @@ async def list_procedure_templates(
|
||||
- **skip**: Number of records to skip (for pagination)
|
||||
- **limit**: Maximum number of records to return
|
||||
"""
|
||||
items, total = crud.get_all(skip=skip, limit=limit)
|
||||
items, total = await crud.get_all(skip=skip, limit=limit)
|
||||
|
||||
return ProcedureTemplateListResponse(
|
||||
items=items,
|
||||
@ -55,7 +55,7 @@ async def get_procedure_template(
|
||||
|
||||
- **procedure_template_id**: The UUID of the proceduretemplate
|
||||
"""
|
||||
db_procedure_template = crud.get_by_id(procedure_template_id)
|
||||
db_procedure_template = await crud.get_by_id(procedure_template_id)
|
||||
if not db_procedure_template:
|
||||
raise HTTPException(
|
||||
status_code=status.HTTP_404_NOT_FOUND,
|
||||
@ -73,7 +73,7 @@ async def create_procedure_template(
|
||||
|
||||
- **procedure_template_in**: The proceduretemplate data to create
|
||||
"""
|
||||
return crud.create(procedure_template_in)
|
||||
return await crud.create(procedure_template_in)
|
||||
|
||||
@router.put("/{ procedure_template_id }", response_model=ProcedureTemplateResponse)
|
||||
async def update_procedure_template(
|
||||
@ -87,13 +87,13 @@ async def update_procedure_template(
|
||||
- **procedure_template_id**: The UUID of the proceduretemplate to update
|
||||
- **procedure_template_in**: The updated proceduretemplate data
|
||||
"""
|
||||
db_procedure_template = crud.get_by_id(procedure_template_id)
|
||||
db_procedure_template = await crud.get_by_id(procedure_template_id)
|
||||
if not db_procedure_template:
|
||||
raise HTTPException(
|
||||
status_code=status.HTTP_404_NOT_FOUND,
|
||||
detail=f"ProcedureTemplate with id { procedure_template_id} not found"
|
||||
)
|
||||
return crud.update(procedure_template_id, procedure_template_in)
|
||||
return await crud.update(procedure_template_id, procedure_template_in)
|
||||
|
||||
@router.delete("/{ procedure_template_id }", status_code=status.HTTP_204_NO_CONTENT)
|
||||
async def delete_procedure_template(
|
||||
@ -105,11 +105,11 @@ async def delete_procedure_template(
|
||||
|
||||
- **procedure_template_id**: The UUID of the proceduretemplate to delete
|
||||
"""
|
||||
db_procedure_template = crud.get_by_id(procedure_template_id)
|
||||
db_procedure_template = await crud.get_by_id(procedure_template_id)
|
||||
if not db_procedure_template:
|
||||
raise HTTPException(
|
||||
status_code=status.HTTP_404_NOT_FOUND,
|
||||
detail=f"ProcedureTemplate with id { procedure_template_id} not found"
|
||||
)
|
||||
crud.delete(procedure_template_id)
|
||||
await crud.delete(procedure_template_id)
|
||||
return None
|
||||
|
||||
@ -35,7 +35,7 @@ async def list_rag_documents(
|
||||
- **skip**: Number of records to skip (for pagination)
|
||||
- **limit**: Maximum number of records to return
|
||||
"""
|
||||
items, total = crud.get_all(skip=skip, limit=limit)
|
||||
items, total = await crud.get_all(skip=skip, limit=limit)
|
||||
|
||||
return RAGDocumentListResponse(
|
||||
items=items,
|
||||
@ -55,7 +55,7 @@ async def get_rag_document(
|
||||
|
||||
- **rag_document_id**: The UUID of the ragdocument
|
||||
"""
|
||||
db_rag_document = crud.get_by_id(rag_document_id)
|
||||
db_rag_document = await crud.get_by_id(rag_document_id)
|
||||
if not db_rag_document:
|
||||
raise HTTPException(
|
||||
status_code=status.HTTP_404_NOT_FOUND,
|
||||
@ -73,7 +73,7 @@ async def create_rag_document(
|
||||
|
||||
- **rag_document_in**: The ragdocument data to create
|
||||
"""
|
||||
return crud.create(rag_document_in)
|
||||
return await crud.create(rag_document_in)
|
||||
|
||||
@router.put("/{ rag_document_id }", response_model=RAGDocumentResponse)
|
||||
async def update_rag_document(
|
||||
@ -87,13 +87,13 @@ async def update_rag_document(
|
||||
- **rag_document_id**: The UUID of the ragdocument to update
|
||||
- **rag_document_in**: The updated ragdocument data
|
||||
"""
|
||||
db_rag_document = crud.get_by_id(rag_document_id)
|
||||
db_rag_document = await crud.get_by_id(rag_document_id)
|
||||
if not db_rag_document:
|
||||
raise HTTPException(
|
||||
status_code=status.HTTP_404_NOT_FOUND,
|
||||
detail=f"RAGDocument with id { rag_document_id} not found"
|
||||
)
|
||||
return crud.update(rag_document_id, rag_document_in)
|
||||
return await crud.update(rag_document_id, rag_document_in)
|
||||
|
||||
@router.delete("/{ rag_document_id }", status_code=status.HTTP_204_NO_CONTENT)
|
||||
async def delete_rag_document(
|
||||
@ -105,11 +105,11 @@ async def delete_rag_document(
|
||||
|
||||
- **rag_document_id**: The UUID of the ragdocument to delete
|
||||
"""
|
||||
db_rag_document = crud.get_by_id(rag_document_id)
|
||||
db_rag_document = await crud.get_by_id(rag_document_id)
|
||||
if not db_rag_document:
|
||||
raise HTTPException(
|
||||
status_code=status.HTTP_404_NOT_FOUND,
|
||||
detail=f"RAGDocument with id { rag_document_id} not found"
|
||||
)
|
||||
crud.delete(rag_document_id)
|
||||
await crud.delete(rag_document_id)
|
||||
return None
|
||||
|
||||
@ -1,115 +0,0 @@
|
||||
"""
|
||||
Transcript API Router
|
||||
Enterprise-grade FastAPI router with full CRUD operations
|
||||
Architecture: Routers → Services/CRUD → SQLAlchemy Models + Pydantic Schemas
|
||||
"""
|
||||
from typing import List, Optional
|
||||
from fastapi import APIRouter, Depends, HTTPException, Query, status
|
||||
from sqlalchemy.orm import Session
|
||||
from uuid import UUID
|
||||
|
||||
from src.config.database import get_db
|
||||
from src.services.transcript_service import TranscriptCRUD
|
||||
from src.validation.transcript_schemas import (
|
||||
TranscriptCreate,
|
||||
TranscriptUpdate,
|
||||
TranscriptResponse,
|
||||
TranscriptListResponse,
|
||||
)
|
||||
|
||||
router = APIRouter(prefix="/transcripts", tags=["Transcript"])
|
||||
|
||||
def get_crud(db: Session = Depends(get_db)) -> TranscriptCRUD:
|
||||
"""Dependency injection for TranscriptCRUD"""
|
||||
return TranscriptCRUD(db)
|
||||
|
||||
@router.get("/", response_model=TranscriptListResponse)
|
||||
async def list_transcripts(
|
||||
skip: int = Query(0, ge=0, description="Number of records to skip"),
|
||||
limit: int = Query(100, ge=1, le=1000, description="Maximum records to return"),
|
||||
crud: TranscriptCRUD = Depends(get_crud),
|
||||
):
|
||||
"""
|
||||
List all transcripts with pagination and filtering.
|
||||
|
||||
- **skip**: Number of records to skip (for pagination)
|
||||
- **limit**: Maximum number of records to return
|
||||
"""
|
||||
items, total = crud.get_all(skip=skip, limit=limit)
|
||||
|
||||
return TranscriptListResponse(
|
||||
items=items,
|
||||
total=total,
|
||||
skip=skip,
|
||||
limit=limit,
|
||||
has_more=skip + limit < total
|
||||
)
|
||||
|
||||
@router.get("/{ transcript_id }", response_model=TranscriptResponse)
|
||||
async def get_transcript(
|
||||
transcript_id: UUID,
|
||||
crud: TranscriptCRUD = Depends(get_crud),
|
||||
):
|
||||
"""
|
||||
Get a specific transcript by ID.
|
||||
|
||||
- **transcript_id**: The UUID of the transcript
|
||||
"""
|
||||
db_transcript = crud.get_by_id(transcript_id)
|
||||
if not db_transcript:
|
||||
raise HTTPException(
|
||||
status_code=status.HTTP_404_NOT_FOUND,
|
||||
detail=f"Transcript with id { transcript_id} not found"
|
||||
)
|
||||
return db_transcript
|
||||
|
||||
@router.post("/", response_model=TranscriptResponse, status_code=status.HTTP_201_CREATED)
|
||||
async def create_transcript(
|
||||
transcript_in: TranscriptCreate,
|
||||
crud: TranscriptCRUD = Depends(get_crud),
|
||||
):
|
||||
"""
|
||||
Create a new transcript.
|
||||
|
||||
- **transcript_in**: The transcript data to create
|
||||
"""
|
||||
return crud.create(transcript_in)
|
||||
|
||||
@router.put("/{ transcript_id }", response_model=TranscriptResponse)
|
||||
async def update_transcript(
|
||||
transcript_id: UUID,
|
||||
transcript_in: TranscriptUpdate,
|
||||
crud: TranscriptCRUD = Depends(get_crud),
|
||||
):
|
||||
"""
|
||||
Update an existing transcript.
|
||||
|
||||
- **transcript_id**: The UUID of the transcript to update
|
||||
- **transcript_in**: The updated transcript data
|
||||
"""
|
||||
db_transcript = crud.get_by_id(transcript_id)
|
||||
if not db_transcript:
|
||||
raise HTTPException(
|
||||
status_code=status.HTTP_404_NOT_FOUND,
|
||||
detail=f"Transcript with id { transcript_id} not found"
|
||||
)
|
||||
return crud.update(transcript_id, transcript_in)
|
||||
|
||||
@router.delete("/{ transcript_id }", status_code=status.HTTP_204_NO_CONTENT)
|
||||
async def delete_transcript(
|
||||
transcript_id: UUID,
|
||||
crud: TranscriptCRUD = Depends(get_crud),
|
||||
):
|
||||
"""
|
||||
Delete a transcript.
|
||||
|
||||
- **transcript_id**: The UUID of the transcript to delete
|
||||
"""
|
||||
db_transcript = crud.get_by_id(transcript_id)
|
||||
if not db_transcript:
|
||||
raise HTTPException(
|
||||
status_code=status.HTTP_404_NOT_FOUND,
|
||||
detail=f"Transcript with id { transcript_id} not found"
|
||||
)
|
||||
crud.delete(transcript_id)
|
||||
return None
|
||||
@ -1,115 +0,0 @@
|
||||
"""
|
||||
ProcedureTemplate API Router
|
||||
Enterprise-grade FastAPI router with full CRUD operations
|
||||
Architecture: Routers → Services/CRUD → SQLAlchemy Models + Pydantic Schemas
|
||||
"""
|
||||
from typing import List, Optional
|
||||
from fastapi import APIRouter, Depends, HTTPException, Query, status
|
||||
from sqlalchemy.orm import Session
|
||||
from uuid import UUID
|
||||
|
||||
from src.config.database import get_db
|
||||
from src.services.procedure_template_service import ProcedureTemplateCRUD
|
||||
from src.validation.procedure_template_schemas import (
|
||||
ProcedureTemplateCreate,
|
||||
ProcedureTemplateUpdate,
|
||||
ProcedureTemplateResponse,
|
||||
ProcedureTemplateListResponse,
|
||||
)
|
||||
|
||||
router = APIRouter(prefix="/proceduretemplates", tags=["ProcedureTemplate"])
|
||||
|
||||
def get_crud(db: Session = Depends(get_db)) -> ProcedureTemplateCRUD:
|
||||
"""Dependency injection for ProcedureTemplateCRUD"""
|
||||
return ProcedureTemplateCRUD(db)
|
||||
|
||||
@router.get("/", response_model=ProcedureTemplateListResponse)
|
||||
async def list_procedure_templates(
|
||||
skip: int = Query(0, ge=0, description="Number of records to skip"),
|
||||
limit: int = Query(100, ge=1, le=1000, description="Maximum records to return"),
|
||||
crud: ProcedureTemplateCRUD = Depends(get_crud),
|
||||
):
|
||||
"""
|
||||
List all proceduretemplates with pagination and filtering.
|
||||
|
||||
- **skip**: Number of records to skip (for pagination)
|
||||
- **limit**: Maximum number of records to return
|
||||
"""
|
||||
items, total = crud.get_all(skip=skip, limit=limit)
|
||||
|
||||
return ProcedureTemplateListResponse(
|
||||
items=items,
|
||||
total=total,
|
||||
skip=skip,
|
||||
limit=limit,
|
||||
has_more=skip + limit < total
|
||||
)
|
||||
|
||||
@router.get("/{ procedure_template_id }", response_model=ProcedureTemplateResponse)
|
||||
async def get_procedure_template(
|
||||
procedure_template_id: UUID,
|
||||
crud: ProcedureTemplateCRUD = Depends(get_crud),
|
||||
):
|
||||
"""
|
||||
Get a specific proceduretemplate by ID.
|
||||
|
||||
- **procedure_template_id**: The UUID of the proceduretemplate
|
||||
"""
|
||||
db_procedure_template = crud.get_by_id(procedure_template_id)
|
||||
if not db_procedure_template:
|
||||
raise HTTPException(
|
||||
status_code=status.HTTP_404_NOT_FOUND,
|
||||
detail=f"ProcedureTemplate with id { procedure_template_id} not found"
|
||||
)
|
||||
return db_procedure_template
|
||||
|
||||
@router.post("/", response_model=ProcedureTemplateResponse, status_code=status.HTTP_201_CREATED)
|
||||
async def create_procedure_template(
|
||||
procedure_template_in: ProcedureTemplateCreate,
|
||||
crud: ProcedureTemplateCRUD = Depends(get_crud),
|
||||
):
|
||||
"""
|
||||
Create a new proceduretemplate.
|
||||
|
||||
- **procedure_template_in**: The proceduretemplate data to create
|
||||
"""
|
||||
return crud.create(procedure_template_in)
|
||||
|
||||
@router.put("/{ procedure_template_id }", response_model=ProcedureTemplateResponse)
|
||||
async def update_procedure_template(
|
||||
procedure_template_id: UUID,
|
||||
procedure_template_in: ProcedureTemplateUpdate,
|
||||
crud: ProcedureTemplateCRUD = Depends(get_crud),
|
||||
):
|
||||
"""
|
||||
Update an existing proceduretemplate.
|
||||
|
||||
- **procedure_template_id**: The UUID of the proceduretemplate to update
|
||||
- **procedure_template_in**: The updated proceduretemplate data
|
||||
"""
|
||||
db_procedure_template = crud.get_by_id(procedure_template_id)
|
||||
if not db_procedure_template:
|
||||
raise HTTPException(
|
||||
status_code=status.HTTP_404_NOT_FOUND,
|
||||
detail=f"ProcedureTemplate with id { procedure_template_id} not found"
|
||||
)
|
||||
return crud.update(procedure_template_id, procedure_template_in)
|
||||
|
||||
@router.delete("/{ procedure_template_id }", status_code=status.HTTP_204_NO_CONTENT)
|
||||
async def delete_procedure_template(
|
||||
procedure_template_id: UUID,
|
||||
crud: ProcedureTemplateCRUD = Depends(get_crud),
|
||||
):
|
||||
"""
|
||||
Delete a proceduretemplate.
|
||||
|
||||
- **procedure_template_id**: The UUID of the proceduretemplate to delete
|
||||
"""
|
||||
db_procedure_template = crud.get_by_id(procedure_template_id)
|
||||
if not db_procedure_template:
|
||||
raise HTTPException(
|
||||
status_code=status.HTTP_404_NOT_FOUND,
|
||||
detail=f"ProcedureTemplate with id { procedure_template_id} not found"
|
||||
)
|
||||
crud.delete(procedure_template_id)
|
||||
return None
|
||||
@ -35,7 +35,7 @@ async def list_transcripts(
|
||||
- **skip**: Number of records to skip (for pagination)
|
||||
- **limit**: Maximum number of records to return
|
||||
"""
|
||||
items, total = crud.get_all(skip=skip, limit=limit)
|
||||
items, total = await crud.get_all(skip=skip, limit=limit)
|
||||
|
||||
return TranscriptListResponse(
|
||||
items=items,
|
||||
@ -55,7 +55,7 @@ async def get_transcript(
|
||||
|
||||
- **transcript_id**: The UUID of the transcript
|
||||
"""
|
||||
db_transcript = crud.get_by_id(transcript_id)
|
||||
db_transcript = await crud.get_by_id(transcript_id)
|
||||
if not db_transcript:
|
||||
raise HTTPException(
|
||||
status_code=status.HTTP_404_NOT_FOUND,
|
||||
@ -73,7 +73,7 @@ async def create_transcript(
|
||||
|
||||
- **transcript_in**: The transcript data to create
|
||||
"""
|
||||
return crud.create(transcript_in)
|
||||
return await crud.create(transcript_in)
|
||||
|
||||
@router.put("/{ transcript_id }", response_model=TranscriptResponse)
|
||||
async def update_transcript(
|
||||
@ -87,13 +87,13 @@ async def update_transcript(
|
||||
- **transcript_id**: The UUID of the transcript to update
|
||||
- **transcript_in**: The updated transcript data
|
||||
"""
|
||||
db_transcript = crud.get_by_id(transcript_id)
|
||||
db_transcript = await crud.get_by_id(transcript_id)
|
||||
if not db_transcript:
|
||||
raise HTTPException(
|
||||
status_code=status.HTTP_404_NOT_FOUND,
|
||||
detail=f"Transcript with id { transcript_id} not found"
|
||||
)
|
||||
return crud.update(transcript_id, transcript_in)
|
||||
return await crud.update(transcript_id, transcript_in)
|
||||
|
||||
@router.delete("/{ transcript_id }", status_code=status.HTTP_204_NO_CONTENT)
|
||||
async def delete_transcript(
|
||||
@ -105,11 +105,11 @@ async def delete_transcript(
|
||||
|
||||
- **transcript_id**: The UUID of the transcript to delete
|
||||
"""
|
||||
db_transcript = crud.get_by_id(transcript_id)
|
||||
db_transcript = await crud.get_by_id(transcript_id)
|
||||
if not db_transcript:
|
||||
raise HTTPException(
|
||||
status_code=status.HTTP_404_NOT_FOUND,
|
||||
detail=f"Transcript with id { transcript_id} not found"
|
||||
)
|
||||
crud.delete(transcript_id)
|
||||
await crud.delete(transcript_id)
|
||||
return None
|
||||
|
||||
@ -35,7 +35,7 @@ async def list_users(
|
||||
- **skip**: Number of records to skip (for pagination)
|
||||
- **limit**: Maximum number of records to return
|
||||
"""
|
||||
items, total = crud.get_all(skip=skip, limit=limit)
|
||||
items, total = await crud.get_all(skip=skip, limit=limit)
|
||||
|
||||
return UserListResponse(
|
||||
items=items,
|
||||
@ -55,7 +55,7 @@ async def get_user(
|
||||
|
||||
- **user_id**: The UUID of the user
|
||||
"""
|
||||
db_user = crud.get_by_id(user_id)
|
||||
db_user = await crud.get_by_id(user_id)
|
||||
if not db_user:
|
||||
raise HTTPException(
|
||||
status_code=status.HTTP_404_NOT_FOUND,
|
||||
@ -73,7 +73,7 @@ async def create_user(
|
||||
|
||||
- **user_in**: The user data to create
|
||||
"""
|
||||
return crud.create(user_in)
|
||||
return await crud.create(user_in)
|
||||
|
||||
@router.put("/{ user_id }", response_model=UserResponse)
|
||||
async def update_user(
|
||||
@ -87,13 +87,13 @@ async def update_user(
|
||||
- **user_id**: The UUID of the user to update
|
||||
- **user_in**: The updated user data
|
||||
"""
|
||||
db_user = crud.get_by_id(user_id)
|
||||
db_user = await crud.get_by_id(user_id)
|
||||
if not db_user:
|
||||
raise HTTPException(
|
||||
status_code=status.HTTP_404_NOT_FOUND,
|
||||
detail=f"User with id { user_id} not found"
|
||||
)
|
||||
return crud.update(user_id, user_in)
|
||||
return await crud.update(user_id, user_in)
|
||||
|
||||
@router.delete("/{ user_id }", status_code=status.HTTP_204_NO_CONTENT)
|
||||
async def delete_user(
|
||||
@ -105,11 +105,11 @@ async def delete_user(
|
||||
|
||||
- **user_id**: The UUID of the user to delete
|
||||
"""
|
||||
db_user = crud.get_by_id(user_id)
|
||||
db_user = await crud.get_by_id(user_id)
|
||||
if not db_user:
|
||||
raise HTTPException(
|
||||
status_code=status.HTTP_404_NOT_FOUND,
|
||||
detail=f"User with id { user_id} not found"
|
||||
)
|
||||
crud.delete(user_id)
|
||||
await crud.delete(user_id)
|
||||
return None
|
||||
|
||||
@ -1,7 +1,8 @@
|
||||
from datetime import date, datetime
|
||||
"""
|
||||
AudioRecording Service Layer
|
||||
Enterprise-grade service with business logic, validation, and error handling
|
||||
Architecture: Routers → Services/CRUD → SQLAlchemy Models + Pydantic Schemas
|
||||
Architecture: Any → Services/CRUD → SQLAlchemy Models + Pydantic Schemas
|
||||
"""
|
||||
from typing import List, Optional, Tuple, Dict, Any
|
||||
from uuid import UUID
|
||||
@ -14,7 +15,7 @@ from src.validation.audio_recording_schemas import AudioRecordingCreate, AudioRe
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
class AudioRecordingService:
|
||||
class AudioRecordingCRUD:
|
||||
"""
|
||||
Service class for AudioRecording business logic.
|
||||
|
||||
@ -22,7 +23,7 @@ class AudioRecordingService:
|
||||
and complex queries.
|
||||
"""
|
||||
|
||||
def __init__(self, db: Session):
|
||||
def __init__(self, db: Any):
|
||||
"""Initialize service with database session."""
|
||||
self.db = db
|
||||
|
||||
@ -38,11 +39,11 @@ class AudioRecordingService:
|
||||
Get all audiorecordings with pagination and filtering.
|
||||
|
||||
Args:
|
||||
skip: Number of records to skip
|
||||
limit: Maximum records to return
|
||||
filters: Dictionary of field filters
|
||||
order_by: Field to order by
|
||||
order_desc: Order descending if True
|
||||
skip: Any of records to skip
|
||||
limit: Any records to return
|
||||
filters: Any of field filters
|
||||
order_by: Any to order by
|
||||
order_desc: Any descending if True
|
||||
|
||||
Returns:
|
||||
Tuple of (list of audiorecordings, total count)
|
||||
@ -85,7 +86,7 @@ class AudioRecordingService:
|
||||
Get a specific audiorecording by ID.
|
||||
|
||||
Args:
|
||||
audio_recording_id: The UUID of the audiorecording
|
||||
audio_recording_id: Any UUID of the audiorecording
|
||||
|
||||
Returns:
|
||||
The audiorecording if found, None otherwise
|
||||
@ -95,12 +96,12 @@ class AudioRecordingService:
|
||||
AudioRecording.id == audio_recording_id
|
||||
).first()
|
||||
|
||||
async def create(self, audio_recording_in: AudioRecordingCreate) -> AudioRecording:
|
||||
async def create(self, audio_recording_in: Any) -> Any:
|
||||
"""
|
||||
Create a new audiorecording.
|
||||
|
||||
Args:
|
||||
audio_recording_in: The audiorecording data to create
|
||||
audio_recording_in: Any audiorecording data to create
|
||||
|
||||
Returns:
|
||||
The created audiorecording
|
||||
@ -134,14 +135,14 @@ class AudioRecordingService:
|
||||
async def update(
|
||||
self,
|
||||
audio_recording_id: UUID,
|
||||
audio_recording_in: AudioRecordingUpdate
|
||||
audio_recording_in: Any
|
||||
) -> Optional[AudioRecording]:
|
||||
"""
|
||||
Update an existing audiorecording.
|
||||
|
||||
Args:
|
||||
audio_recording_id: The UUID of the audiorecording to update
|
||||
audio_recording_in: The updated audiorecording data
|
||||
audio_recording_id: Any UUID of the audiorecording to update
|
||||
audio_recording_in: Any updated audiorecording data
|
||||
|
||||
Returns:
|
||||
The updated audiorecording if found, None otherwise
|
||||
@ -177,7 +178,7 @@ class AudioRecordingService:
|
||||
Delete a audiorecording.
|
||||
|
||||
Args:
|
||||
audio_recording_id: The UUID of the audiorecording to delete
|
||||
audio_recording_id: Any UUID of the audiorecording to delete
|
||||
|
||||
Returns:
|
||||
True if deleted, False if not found
|
||||
@ -204,9 +205,9 @@ class AudioRecordingService:
|
||||
Get all audiorecordings for a specific User.
|
||||
|
||||
Args:
|
||||
user_id: The UUID of the User
|
||||
skip: Number of records to skip
|
||||
limit: Maximum records to return
|
||||
user_id: Any UUID of the User
|
||||
skip: Any of records to skip
|
||||
limit: Any records to return
|
||||
|
||||
Returns:
|
||||
Tuple of (list of audiorecordings, total count)
|
||||
@ -230,9 +231,9 @@ class AudioRecordingService:
|
||||
Get all audiorecordings for a specific Patient.
|
||||
|
||||
Args:
|
||||
patient_id: The UUID of the Patient
|
||||
skip: Number of records to skip
|
||||
limit: Maximum records to return
|
||||
patient_id: Any UUID of the Patient
|
||||
skip: Any of records to skip
|
||||
limit: Any records to return
|
||||
|
||||
Returns:
|
||||
Tuple of (list of audiorecordings, total count)
|
||||
@ -256,9 +257,9 @@ class AudioRecordingService:
|
||||
Get all audiorecordings for a specific ProcedureTemplate.
|
||||
|
||||
Args:
|
||||
procedure_template_id: The UUID of the ProcedureTemplate
|
||||
skip: Number of records to skip
|
||||
limit: Maximum records to return
|
||||
procedure_template_id: Any UUID of the ProcedureTemplate
|
||||
skip: Any of records to skip
|
||||
limit: Any records to return
|
||||
|
||||
Returns:
|
||||
Tuple of (list of audiorecordings, total count)
|
||||
@ -279,7 +280,7 @@ class AudioRecordingService:
|
||||
@generated from DSL function
|
||||
"""
|
||||
# Auto-generated non-validation rule implementation
|
||||
# MultiSessionConsolidationRule: Consolidate multi-day recordings per encounter
|
||||
# MultiSessionConsolidationRule: Any multi-day recordings per encounter
|
||||
if audio_recording.encounter_id is not None:
|
||||
# Fetch related recordings with the same encounter_id
|
||||
related_recordings = await audio_recording_service.find_by_condition(
|
||||
@ -315,7 +316,7 @@ class AudioRecordingService:
|
||||
@generated from DSL function
|
||||
"""
|
||||
# Auto-generated non-validation rule implementation
|
||||
# EncryptionAtRestRule: AES-256 encryption for all PHI at rest
|
||||
# EncryptionAtRestRule: Any-256 encryption for all PHI at rest
|
||||
if not audiorecording.is_encrypted:
|
||||
# Encrypt the audio file at the given file path
|
||||
encrypted_data = AES256.encrypt(audiorecording.file_path)
|
||||
@ -330,7 +331,7 @@ class AudioRecordingService:
|
||||
encryption_key = AES256.generate_key_id()
|
||||
audiorecording.encryption_key_id = encryption_key
|
||||
|
||||
async def validateAudioFormat(self, audio_recording_in: AudioRecordingCreate, existing: Optional[AudioRecording] = None) -> Any:
|
||||
async def validateAudioFormat(self, audio_recording_in: Any, existing: Optional[AudioRecording] = None) -> Any:
|
||||
"""
|
||||
Support AAC, MP3, WAV formats only
|
||||
@generated from DSL function
|
||||
@ -346,13 +347,13 @@ class AudioRecordingService:
|
||||
tenant_id = audio_recording_data.get('tenant_id')
|
||||
version = audio_recording_data.get('version')
|
||||
context = {'user': {'tenant_id': tenant_id}}
|
||||
# AudioFormatValidationRule: Support AAC, MP3, WAV formats only
|
||||
# AudioFormatValidationRule: Any AAC, MP3, WAV formats only
|
||||
allowed_formats = ['AAC', 'MP3', 'WAV']
|
||||
upper_format = audio_recording.file_format.upper()
|
||||
if upper_format not in allowed_formats:
|
||||
raise ValueError("Invalid audio format. Only AAC, MP3, and WAV formats are supported.")
|
||||
|
||||
async def requiresPatientAssociation(self, audio_recording_in: AudioRecordingCreate, existing: Optional[AudioRecording] = None) -> Any:
|
||||
async def requiresPatientAssociation(self, audio_recording_in: Any, existing: Optional[AudioRecording] = None) -> Any:
|
||||
"""
|
||||
Recording must associate with patient MRN/encounter
|
||||
@generated from DSL function
|
||||
@ -368,11 +369,11 @@ class AudioRecordingService:
|
||||
tenant_id = audio_recording_data.get('tenant_id')
|
||||
version = audio_recording_data.get('version')
|
||||
context = {'user': {'tenant_id': tenant_id}}
|
||||
# PatientAssociationRule: Recording must associate with patient MRN/encounter
|
||||
# PatientAssociationRule: Any must associate with patient MRN/encounter
|
||||
if recording.patient_id is None and recording.encounter_id is None:
|
||||
raise ValueError("Recording must be associated with either a patient (patient_id) or an encounter (encounter_id)")
|
||||
|
||||
async def shouldAutoUpload(self, audio_recording_in: AudioRecordingCreate, existing: Optional[AudioRecording] = None) -> Any:
|
||||
async def shouldAutoUpload(self, audio_recording_in: Any, existing: Optional[AudioRecording] = None) -> Any:
|
||||
"""
|
||||
Auto-upload recordings when network available
|
||||
@generated from DSL function
|
||||
@ -395,7 +396,7 @@ class AudioRecordingService:
|
||||
# If network is available, proceed with auto-upload logic
|
||||
# The rule passes when network is available
|
||||
|
||||
async def allowMultipleRecordings(self, audio_recording_in: AudioRecordingCreate, existing: Optional[AudioRecording] = None) -> Any:
|
||||
async def allowMultipleRecordings(self, audio_recording_in: Any, existing: Optional[AudioRecording] = None) -> Any:
|
||||
"""
|
||||
Support multiple recordings per encounter
|
||||
@generated from DSL function
|
||||
@ -411,7 +412,7 @@ class AudioRecordingService:
|
||||
tenant_id = audio_recording_data.get('tenant_id')
|
||||
version = audio_recording_data.get('version')
|
||||
context = {'user': {'tenant_id': tenant_id}}
|
||||
# TODO: Business rule code not generated. Run tertiary analysis to generate code using Claude.
|
||||
# TODO: Any rule code not generated. Run tertiary analysis to generate code using Claude.
|
||||
|
||||
async def applyNoiseReduction(self) -> Any:
|
||||
"""
|
||||
@ -455,7 +456,7 @@ class AudioRecordingService:
|
||||
await event_bus.emit("audio.uploaded", event_data)
|
||||
|
||||
# =========== Custom Service Methods ===========
|
||||
async def find_one(self, _id: UUID) -> AudioRecording:
|
||||
async def find_one(self, _id: UUID) -> Any:
|
||||
"""
|
||||
Get audio recording by ID
|
||||
GET /api/v1/audio/recordings/{id}
|
||||
@ -463,7 +464,7 @@ class AudioRecordingService:
|
||||
# Custom method implementation
|
||||
raise NotImplementedError(f"Method find_one not yet implemented")
|
||||
|
||||
async def upload_audio(self, _id: UUID, _in: Create) -> AudioRecording:
|
||||
async def upload_audio(self, _id: UUID, _in: Any) -> Any:
|
||||
"""
|
||||
Upload audio file
|
||||
POST /api/v1/audio/recordings/{id}/upload
|
||||
@ -471,7 +472,7 @@ class AudioRecordingService:
|
||||
# Custom method implementation
|
||||
raise NotImplementedError(f"Method upload_audio not yet implemented")
|
||||
|
||||
async def download_audio(self, _id: UUID) -> AudioRecording:
|
||||
async def download_audio(self, _id: UUID) -> Any:
|
||||
"""
|
||||
Download audio file
|
||||
GET /api/v1/audio/recordings/{id}/download
|
||||
@ -479,7 +480,7 @@ class AudioRecordingService:
|
||||
# Custom method implementation
|
||||
raise NotImplementedError(f"Method download_audio not yet implemented")
|
||||
|
||||
async def uploadAudio(self, _id: UUID, file: Any) -> AudioRecording:
|
||||
async def uploadAudio(self, _id: UUID, file: Any) -> Any:
|
||||
"""
|
||||
Upload audio file
|
||||
custom
|
||||
@ -549,7 +550,7 @@ class AudioRecordingService:
|
||||
"message": "Audio file uploaded successfully"
|
||||
}
|
||||
|
||||
async def findByPatient(self, patient_id: Any) -> AudioRecording:
|
||||
async def findByPatient(self, patient_id: Any) -> Any:
|
||||
"""
|
||||
Get recordings by patient
|
||||
custom
|
||||
@ -560,7 +561,7 @@ class AudioRecordingService:
|
||||
recordings = result.scalars().all()
|
||||
return list(recordings)
|
||||
|
||||
async def encryptAudio(self, file_path: Any) -> AudioRecording:
|
||||
async def encryptAudio(self, file_path: Any) -> Any:
|
||||
"""
|
||||
Encrypt audio file AES-256
|
||||
custom
|
||||
@ -627,7 +628,7 @@ class AudioRecordingService:
|
||||
|
||||
return encrypted_file_path
|
||||
|
||||
async def validateFormat(self, format: Any) -> AudioRecording:
|
||||
async def validateFormat(self, format: Any) -> Any:
|
||||
"""
|
||||
Validate audio format
|
||||
custom
|
||||
@ -637,10 +638,10 @@ class AudioRecordingService:
|
||||
Validate audio format against supported formats.
|
||||
|
||||
Args:
|
||||
format: Audio format string to validate
|
||||
format: Any format string to validate
|
||||
|
||||
Returns:
|
||||
bool: True if format is valid, False otherwise
|
||||
bool: Any if format is valid, False otherwise
|
||||
"""
|
||||
# Define supported audio formats
|
||||
supported_formats = {
|
||||
@ -654,7 +655,7 @@ class AudioRecordingService:
|
||||
# Check if format is in supported formats
|
||||
return normalized_format in supported_formats
|
||||
|
||||
async def encrypt(self, file_path: Any, key_id: Any = None) -> AudioRecording:
|
||||
async def encrypt(self, file_path: Any, key_id: Any = None) -> Any:
|
||||
"""
|
||||
Encrypt audio AES-256
|
||||
custom
|
||||
@ -721,7 +722,7 @@ class AudioRecordingService:
|
||||
|
||||
return encrypted_file_path
|
||||
|
||||
async def decrypt(self, file_path: Any, key_id: Any) -> AudioRecording:
|
||||
async def decrypt(self, file_path: Any, key_id: Any) -> Any:
|
||||
"""
|
||||
Decrypt audio file
|
||||
custom
|
||||
@ -804,7 +805,7 @@ class AudioRecordingService:
|
||||
detail=f"Failed to decrypt audio file: {str(e)}"
|
||||
)
|
||||
|
||||
async def generateKey(self, ) -> AudioRecording:
|
||||
async def generateKey(self, ) -> Any:
|
||||
"""
|
||||
Generate encryption key
|
||||
custom
|
||||
@ -817,11 +818,11 @@ class AudioRecordingService:
|
||||
key_id = f"key_{uuid.uuid4().hex[:16]}"
|
||||
|
||||
# Return the encryption key
|
||||
# Note: In production, this key should be stored securely in a key management service
|
||||
# Note: Any production, this key should be stored securely in a key management service
|
||||
# and only the key_id should be stored in the database
|
||||
return encryption_key
|
||||
|
||||
async def rotateKey(self, old_key_id: Any) -> AudioRecording:
|
||||
async def rotateKey(self, old_key_id: Any) -> Any:
|
||||
"""
|
||||
Rotate encryption key
|
||||
custom
|
||||
@ -864,7 +865,7 @@ class AudioRecordingService:
|
||||
|
||||
return new_key_id
|
||||
|
||||
async def upload(self, file: Any, recording_id: Any) -> AudioRecording:
|
||||
async def upload(self, file: Any, recording_id: Any) -> Any:
|
||||
"""
|
||||
Upload audio file
|
||||
custom
|
||||
@ -941,7 +942,7 @@ class AudioRecordingService:
|
||||
"message": "Audio file uploaded successfully"
|
||||
}
|
||||
|
||||
async def validateFile(self, file: Any, format: Any) -> AudioRecording:
|
||||
async def validateFile(self, file: Any, format: Any) -> Any:
|
||||
"""
|
||||
Validate audio file
|
||||
custom
|
||||
@ -1003,7 +1004,7 @@ class AudioRecordingService:
|
||||
except Exception as e:
|
||||
return False
|
||||
|
||||
async def getUploadUrl(self, recording_id: Any) -> AudioRecording:
|
||||
async def getUploadUrl(self, recording_id: Any) -> Any:
|
||||
"""
|
||||
Get presigned upload URL
|
||||
custom
|
||||
@ -1058,7 +1059,7 @@ class AudioRecordingService:
|
||||
detail=f"Failed to generate presigned URL: {str(e)}"
|
||||
)
|
||||
|
||||
async def processUpload(self, recording_id: Any) -> AudioRecording:
|
||||
async def processUpload(self, recording_id: Any) -> Any:
|
||||
"""
|
||||
Process uploaded file
|
||||
custom
|
||||
@ -1144,7 +1145,7 @@ class AudioRecordingService:
|
||||
)
|
||||
|
||||
# =========== Query Methods (findBy*) ===========
|
||||
async def find_by_encounter_id(self, encounter_id: str) -> List[AudioRecording]:
|
||||
async def find_by_encounter_id(self, encounter_id: str) -> List[Any]:
|
||||
"""
|
||||
Find audiorecordings by encounter_id
|
||||
"""
|
||||
@ -1152,7 +1153,7 @@ class AudioRecordingService:
|
||||
getattr(AudioRecording, "encounter_id") == encounter_id
|
||||
).all()
|
||||
|
||||
async def find_by_file_path(self, file_path: str) -> List[AudioRecording]:
|
||||
async def find_by_file_path(self, file_path: str) -> List[Any]:
|
||||
"""
|
||||
Find audiorecordings by file_path
|
||||
"""
|
||||
@ -1160,7 +1161,7 @@ class AudioRecordingService:
|
||||
getattr(AudioRecording, "file_path") == file_path
|
||||
).all()
|
||||
|
||||
async def find_by_file_name(self, file_name: str) -> List[AudioRecording]:
|
||||
async def find_by_file_name(self, file_name: str) -> List[Any]:
|
||||
"""
|
||||
Find audiorecordings by file_name
|
||||
"""
|
||||
@ -1168,7 +1169,7 @@ class AudioRecordingService:
|
||||
getattr(AudioRecording, "file_name") == file_name
|
||||
).all()
|
||||
|
||||
async def find_by_file_format(self, file_format: str) -> List[AudioRecording]:
|
||||
async def find_by_file_format(self, file_format: str) -> List[Any]:
|
||||
"""
|
||||
Find audiorecordings by file_format
|
||||
"""
|
||||
@ -1176,7 +1177,7 @@ class AudioRecordingService:
|
||||
getattr(AudioRecording, "file_format") == file_format
|
||||
).all()
|
||||
|
||||
async def find_by_file_size_bytes(self, file_size_bytes: int) -> List[AudioRecording]:
|
||||
async def find_by_file_size_bytes(self, file_size_bytes: int) -> List[Any]:
|
||||
"""
|
||||
Find audiorecordings by file_size_bytes
|
||||
"""
|
||||
@ -1184,7 +1185,7 @@ class AudioRecordingService:
|
||||
getattr(AudioRecording, "file_size_bytes") == file_size_bytes
|
||||
).all()
|
||||
|
||||
async def find_by_duration_seconds(self, duration_seconds: int) -> List[AudioRecording]:
|
||||
async def find_by_duration_seconds(self, duration_seconds: int) -> List[Any]:
|
||||
"""
|
||||
Find audiorecordings by duration_seconds
|
||||
"""
|
||||
@ -1192,7 +1193,7 @@ class AudioRecordingService:
|
||||
getattr(AudioRecording, "duration_seconds") == duration_seconds
|
||||
).all()
|
||||
|
||||
async def find_by_recording_date(self, recording_date: datetime) -> List[AudioRecording]:
|
||||
async def find_by_recording_date(self, recording_date: datetime) -> List[Any]:
|
||||
"""
|
||||
Find audiorecordings by recording_date
|
||||
"""
|
||||
@ -1200,7 +1201,7 @@ class AudioRecordingService:
|
||||
getattr(AudioRecording, "recording_date") == recording_date
|
||||
).all()
|
||||
|
||||
async def find_by_upload_date(self, upload_date: datetime) -> List[AudioRecording]:
|
||||
async def find_by_upload_date(self, upload_date: datetime) -> List[Any]:
|
||||
"""
|
||||
Find audiorecordings by upload_date
|
||||
"""
|
||||
@ -1208,7 +1209,7 @@ class AudioRecordingService:
|
||||
getattr(AudioRecording, "upload_date") == upload_date
|
||||
).all()
|
||||
|
||||
async def find_by_is_encrypted(self, is_encrypted: bool) -> List[AudioRecording]:
|
||||
async def find_by_is_encrypted(self, is_encrypted: bool) -> List[Any]:
|
||||
"""
|
||||
Find audiorecordings by is_encrypted
|
||||
"""
|
||||
@ -1216,7 +1217,7 @@ class AudioRecordingService:
|
||||
getattr(AudioRecording, "is_encrypted") == is_encrypted
|
||||
).all()
|
||||
|
||||
async def find_by_encryption_key_id(self, encryption_key_id: str) -> List[AudioRecording]:
|
||||
async def find_by_encryption_key_id(self, encryption_key_id: str) -> List[Any]:
|
||||
"""
|
||||
Find audiorecordings by encryption_key_id
|
||||
"""
|
||||
@ -1224,7 +1225,7 @@ class AudioRecordingService:
|
||||
getattr(AudioRecording, "encryption_key_id") == encryption_key_id
|
||||
).all()
|
||||
|
||||
async def find_by_status(self, status: str) -> List[AudioRecording]:
|
||||
async def find_by_status(self, status: str) -> List[Any]:
|
||||
"""
|
||||
Find audiorecordings by status
|
||||
"""
|
||||
@ -1232,7 +1233,7 @@ class AudioRecordingService:
|
||||
getattr(AudioRecording, "status") == status
|
||||
).all()
|
||||
|
||||
async def find_by_device_info(self, device_info: Dict[str, Any]) -> List[AudioRecording]:
|
||||
async def find_by_device_info(self, device_info: Dict[str, Any]) -> List[Any]:
|
||||
"""
|
||||
Find audiorecordings by device_info
|
||||
"""
|
||||
@ -1240,7 +1241,7 @@ class AudioRecordingService:
|
||||
getattr(AudioRecording, "device_info") == device_info
|
||||
).all()
|
||||
|
||||
async def find_by_noise_level(self, noise_level: str) -> List[AudioRecording]:
|
||||
async def find_by_noise_level(self, noise_level: str) -> List[Any]:
|
||||
"""
|
||||
Find audiorecordings by noise_level
|
||||
"""
|
||||
@ -1248,7 +1249,7 @@ class AudioRecordingService:
|
||||
getattr(AudioRecording, "noise_level") == noise_level
|
||||
).all()
|
||||
|
||||
async def find_by_is_template_based(self, is_template_based: bool) -> List[AudioRecording]:
|
||||
async def find_by_is_template_based(self, is_template_based: bool) -> List[Any]:
|
||||
"""
|
||||
Find audiorecordings by is_template_based
|
||||
"""
|
||||
@ -1256,7 +1257,7 @@ class AudioRecordingService:
|
||||
getattr(AudioRecording, "is_template_based") == is_template_based
|
||||
).all()
|
||||
|
||||
async def find_by_created_at(self, created_at: datetime) -> List[AudioRecording]:
|
||||
async def find_by_created_at(self, created_at: datetime) -> List[Any]:
|
||||
"""
|
||||
Find audiorecordings by created_at
|
||||
"""
|
||||
@ -1264,7 +1265,7 @@ class AudioRecordingService:
|
||||
getattr(AudioRecording, "created_at") == created_at
|
||||
).all()
|
||||
|
||||
async def find_by_updated_at(self, updated_at: datetime) -> List[AudioRecording]:
|
||||
async def find_by_updated_at(self, updated_at: datetime) -> List[Any]:
|
||||
"""
|
||||
Find audiorecordings by updated_at
|
||||
"""
|
||||
@ -1273,7 +1274,7 @@ class AudioRecordingService:
|
||||
).all()
|
||||
|
||||
# =========== Relationship Methods ===========
|
||||
async def get_by_user_id(self, audio_recording_id: UUID) -> User:
|
||||
async def get_by_user_id(self, audio_recording_id: UUID) -> Any:
|
||||
"""
|
||||
Get the user for this audiorecording
|
||||
"""
|
||||
@ -1288,7 +1289,7 @@ class AudioRecordingService:
|
||||
).first()
|
||||
return None
|
||||
|
||||
async def get_by_patient_id(self, audio_recording_id: UUID) -> Patient:
|
||||
async def get_by_patient_id(self, audio_recording_id: UUID) -> Any:
|
||||
"""
|
||||
Get the patient for this audiorecording
|
||||
"""
|
||||
@ -1303,7 +1304,7 @@ class AudioRecordingService:
|
||||
).first()
|
||||
return None
|
||||
|
||||
async def get_by_template_id(self, audio_recording_id: UUID) -> ProcedureTemplate:
|
||||
async def get_by_template_id(self, audio_recording_id: UUID) -> Any:
|
||||
"""
|
||||
Get the proceduretemplate for this audiorecording
|
||||
"""
|
||||
@ -1318,7 +1319,7 @@ class AudioRecordingService:
|
||||
).first()
|
||||
return None
|
||||
|
||||
async def get_by_audio_recording_id(self, audio_recording_id: UUID) -> Transcript:
|
||||
async def get_by_audio_recording_id(self, audio_recording_id: UUID) -> Any:
|
||||
"""
|
||||
Get the transcript for this audiorecording
|
||||
"""
|
||||
@ -1,7 +1,8 @@
|
||||
from datetime import date, datetime
|
||||
"""
|
||||
AuditLog Service Layer
|
||||
Enterprise-grade service with business logic, validation, and error handling
|
||||
Architecture: Routers → Services/CRUD → SQLAlchemy Models + Pydantic Schemas
|
||||
Architecture: Any → Services/CRUD → SQLAlchemy Models + Pydantic Schemas
|
||||
"""
|
||||
from typing import List, Optional, Tuple, Dict, Any
|
||||
from uuid import UUID
|
||||
@ -14,7 +15,7 @@ from src.validation.audit_log_schemas import AuditLogCreate, AuditLogUpdate
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
class AuditLogService:
|
||||
class AuditLogCRUD:
|
||||
"""
|
||||
Service class for AuditLog business logic.
|
||||
|
||||
@ -22,7 +23,7 @@ class AuditLogService:
|
||||
and complex queries.
|
||||
"""
|
||||
|
||||
def __init__(self, db: Session):
|
||||
def __init__(self, db: Any):
|
||||
"""Initialize service with database session."""
|
||||
self.db = db
|
||||
|
||||
@ -38,11 +39,11 @@ class AuditLogService:
|
||||
Get all auditlogs with pagination and filtering.
|
||||
|
||||
Args:
|
||||
skip: Number of records to skip
|
||||
limit: Maximum records to return
|
||||
filters: Dictionary of field filters
|
||||
order_by: Field to order by
|
||||
order_desc: Order descending if True
|
||||
skip: Any of records to skip
|
||||
limit: Any records to return
|
||||
filters: Any of field filters
|
||||
order_by: Any to order by
|
||||
order_desc: Any descending if True
|
||||
|
||||
Returns:
|
||||
Tuple of (list of auditlogs, total count)
|
||||
@ -85,7 +86,7 @@ class AuditLogService:
|
||||
Get a specific auditlog by ID.
|
||||
|
||||
Args:
|
||||
audit_log_id: The UUID of the auditlog
|
||||
audit_log_id: Any UUID of the auditlog
|
||||
|
||||
Returns:
|
||||
The auditlog if found, None otherwise
|
||||
@ -95,12 +96,12 @@ class AuditLogService:
|
||||
AuditLog.id == audit_log_id
|
||||
).first()
|
||||
|
||||
async def create(self, audit_log_in: AuditLogCreate) -> AuditLog:
|
||||
async def create(self, audit_log_in: Any) -> Any:
|
||||
"""
|
||||
Create a new auditlog.
|
||||
|
||||
Args:
|
||||
audit_log_in: The auditlog data to create
|
||||
audit_log_in: Any auditlog data to create
|
||||
|
||||
Returns:
|
||||
The created auditlog
|
||||
@ -128,14 +129,14 @@ class AuditLogService:
|
||||
async def update(
|
||||
self,
|
||||
audit_log_id: UUID,
|
||||
audit_log_in: AuditLogUpdate
|
||||
audit_log_in: Any
|
||||
) -> Optional[AuditLog]:
|
||||
"""
|
||||
Update an existing auditlog.
|
||||
|
||||
Args:
|
||||
audit_log_id: The UUID of the auditlog to update
|
||||
audit_log_in: The updated auditlog data
|
||||
audit_log_id: Any UUID of the auditlog to update
|
||||
audit_log_in: Any updated auditlog data
|
||||
|
||||
Returns:
|
||||
The updated auditlog if found, None otherwise
|
||||
@ -163,7 +164,7 @@ class AuditLogService:
|
||||
Delete a auditlog.
|
||||
|
||||
Args:
|
||||
audit_log_id: The UUID of the auditlog to delete
|
||||
audit_log_id: Any UUID of the auditlog to delete
|
||||
|
||||
Returns:
|
||||
True if deleted, False if not found
|
||||
@ -190,9 +191,9 @@ class AuditLogService:
|
||||
Get all auditlogs for a specific User.
|
||||
|
||||
Args:
|
||||
user_id: The UUID of the User
|
||||
skip: Number of records to skip
|
||||
limit: Maximum records to return
|
||||
user_id: Any UUID of the User
|
||||
skip: Any of records to skip
|
||||
limit: Any records to return
|
||||
|
||||
Returns:
|
||||
Tuple of (list of auditlogs, total count)
|
||||
@ -276,7 +277,7 @@ class AuditLogService:
|
||||
await event_bus.emit("phi.accessed", event_data)
|
||||
|
||||
# =========== Custom Service Methods ===========
|
||||
async def find_one(self, _id: UUID) -> AuditLog:
|
||||
async def find_one(self, _id: UUID) -> Any:
|
||||
"""
|
||||
Get audit log by ID
|
||||
GET /api/v1/audit/logs/{id}
|
||||
@ -284,7 +285,7 @@ class AuditLogService:
|
||||
# Custom method implementation
|
||||
raise NotImplementedError(f"Method find_one not yet implemented")
|
||||
|
||||
async def get_entity_history(self, entity_type: Any, entity_id: Any) -> List[AuditLog]:
|
||||
async def get_entity_history(self, entity_type: Any, entity_id: Any) -> List[Any]:
|
||||
"""
|
||||
Get entity audit history
|
||||
GET /api/v1/audit/logs/entity/{entity_type}/{entity_id}
|
||||
@ -292,7 +293,7 @@ class AuditLogService:
|
||||
# Custom method implementation
|
||||
raise NotImplementedError(f"Method get_entity_history not yet implemented")
|
||||
|
||||
async def get_user_activity(self, user_id: Any, date_from: Any, date_to: Any) -> List[AuditLog]:
|
||||
async def get_user_activity(self, user_id: Any, date_from: Any, date_to: Any) -> List[Any]:
|
||||
"""
|
||||
Get user activity
|
||||
GET /api/v1/audit/logs/user/{user_id}
|
||||
@ -300,7 +301,7 @@ class AuditLogService:
|
||||
# Custom method implementation
|
||||
raise NotImplementedError(f"Method get_user_activity not yet implemented")
|
||||
|
||||
async def export_logs(self, _in: Create) -> AuditLog:
|
||||
async def export_logs(self, _in: Any) -> Any:
|
||||
"""
|
||||
Export audit logs
|
||||
POST /api/v1/audit/logs/export
|
||||
@ -308,7 +309,7 @@ class AuditLogService:
|
||||
# Custom method implementation
|
||||
raise NotImplementedError(f"Method export_logs not yet implemented")
|
||||
|
||||
async def exportLogs(self, filters: Any, format: Any) -> AuditLog:
|
||||
async def exportLogs(self, filters: Any, format: Any) -> Any:
|
||||
"""
|
||||
Export audit logs
|
||||
custom
|
||||
@ -414,7 +415,7 @@ class AuditLogService:
|
||||
else:
|
||||
raise HTTPException(status_code=400, detail=f"Unsupported export format: {format}")
|
||||
|
||||
async def findByUser(self, user_id: Any, skip: Any = 0, take: Any = 10) -> AuditLog:
|
||||
async def findByUser(self, user_id: Any, skip: Any = 0, take: Any = 10) -> Any:
|
||||
"""
|
||||
Get logs by user
|
||||
custom
|
||||
@ -425,7 +426,7 @@ class AuditLogService:
|
||||
audit_logs = result.scalars().all()
|
||||
return audit_logs
|
||||
|
||||
async def findByEntity(self, entity_type: Any, entity_id: Any) -> AuditLog:
|
||||
async def findByEntity(self, entity_type: Any, entity_id: Any) -> Any:
|
||||
"""
|
||||
Get logs by entity
|
||||
custom
|
||||
@ -441,7 +442,7 @@ class AuditLogService:
|
||||
|
||||
return list(audit_logs)
|
||||
|
||||
async def findPHIAccess(self, date_from: Any = None, date_to: Any = None) -> AuditLog:
|
||||
async def findPHIAccess(self, date_from: Any = None, date_to: Any = None) -> Any:
|
||||
"""
|
||||
Get PHI access logs
|
||||
custom
|
||||
@ -464,7 +465,7 @@ class AuditLogService:
|
||||
|
||||
return list(audit_logs)
|
||||
|
||||
async def findByDateRange(self, start_date: Any, end_date: Any) -> AuditLog:
|
||||
async def findByDateRange(self, start_date: Any, end_date: Any) -> Any:
|
||||
"""
|
||||
Get logs by date range
|
||||
custom
|
||||
@ -486,7 +487,7 @@ class AuditLogService:
|
||||
return list(audit_logs)
|
||||
|
||||
# =========== Query Methods (findBy*) ===========
|
||||
async def find_by_entity_type(self, entity_type: str) -> List[AuditLog]:
|
||||
async def find_by_entity_type(self, entity_type: str) -> List[Any]:
|
||||
"""
|
||||
Find auditlogs by entity_type
|
||||
"""
|
||||
@ -494,7 +495,7 @@ class AuditLogService:
|
||||
getattr(AuditLog, "entity_type") == entity_type
|
||||
).all()
|
||||
|
||||
async def find_by_entity_id(self, entity_id: UUID) -> List[AuditLog]:
|
||||
async def find_by_entity_id(self, entity_id: UUID) -> List[Any]:
|
||||
"""
|
||||
Find auditlogs by entity_id
|
||||
"""
|
||||
@ -502,7 +503,7 @@ class AuditLogService:
|
||||
getattr(AuditLog, "entity_id") == entity_id
|
||||
).all()
|
||||
|
||||
async def find_by_action(self, action: str) -> List[AuditLog]:
|
||||
async def find_by_action(self, action: str) -> List[Any]:
|
||||
"""
|
||||
Find auditlogs by action
|
||||
"""
|
||||
@ -510,7 +511,7 @@ class AuditLogService:
|
||||
getattr(AuditLog, "action") == action
|
||||
).all()
|
||||
|
||||
async def find_by_action_category(self, action_category: str) -> List[AuditLog]:
|
||||
async def find_by_action_category(self, action_category: str) -> List[Any]:
|
||||
"""
|
||||
Find auditlogs by action_category
|
||||
"""
|
||||
@ -518,7 +519,7 @@ class AuditLogService:
|
||||
getattr(AuditLog, "action_category") == action_category
|
||||
).all()
|
||||
|
||||
async def find_by_old_values(self, old_values: Dict[str, Any]) -> List[AuditLog]:
|
||||
async def find_by_old_values(self, old_values: Dict[str, Any]) -> List[Any]:
|
||||
"""
|
||||
Find auditlogs by old_values
|
||||
"""
|
||||
@ -526,7 +527,7 @@ class AuditLogService:
|
||||
getattr(AuditLog, "old_values") == old_values
|
||||
).all()
|
||||
|
||||
async def find_by_new_values(self, new_values: Dict[str, Any]) -> List[AuditLog]:
|
||||
async def find_by_new_values(self, new_values: Dict[str, Any]) -> List[Any]:
|
||||
"""
|
||||
Find auditlogs by new_values
|
||||
"""
|
||||
@ -534,7 +535,7 @@ class AuditLogService:
|
||||
getattr(AuditLog, "new_values") == new_values
|
||||
).all()
|
||||
|
||||
async def find_by_changes_summary(self, changes_summary: str) -> List[AuditLog]:
|
||||
async def find_by_changes_summary(self, changes_summary: str) -> List[Any]:
|
||||
"""
|
||||
Find auditlogs by changes_summary
|
||||
"""
|
||||
@ -542,7 +543,7 @@ class AuditLogService:
|
||||
getattr(AuditLog, "changes_summary") == changes_summary
|
||||
).all()
|
||||
|
||||
async def find_by_ip_address(self, ip_address: str) -> List[AuditLog]:
|
||||
async def find_by_ip_address(self, ip_address: str) -> List[Any]:
|
||||
"""
|
||||
Find auditlogs by ip_address
|
||||
"""
|
||||
@ -550,7 +551,7 @@ class AuditLogService:
|
||||
getattr(AuditLog, "ip_address") == ip_address
|
||||
).all()
|
||||
|
||||
async def find_by_user_agent(self, user_agent: str) -> List[AuditLog]:
|
||||
async def find_by_user_agent(self, user_agent: str) -> List[Any]:
|
||||
"""
|
||||
Find auditlogs by user_agent
|
||||
"""
|
||||
@ -558,7 +559,7 @@ class AuditLogService:
|
||||
getattr(AuditLog, "user_agent") == user_agent
|
||||
).all()
|
||||
|
||||
async def find_by_session_id(self, session_id: str) -> List[AuditLog]:
|
||||
async def find_by_session_id(self, session_id: str) -> List[Any]:
|
||||
"""
|
||||
Find auditlogs by session_id
|
||||
"""
|
||||
@ -566,7 +567,7 @@ class AuditLogService:
|
||||
getattr(AuditLog, "session_id") == session_id
|
||||
).all()
|
||||
|
||||
async def find_by_request_id(self, request_id: str) -> List[AuditLog]:
|
||||
async def find_by_request_id(self, request_id: str) -> List[Any]:
|
||||
"""
|
||||
Find auditlogs by request_id
|
||||
"""
|
||||
@ -574,7 +575,7 @@ class AuditLogService:
|
||||
getattr(AuditLog, "request_id") == request_id
|
||||
).all()
|
||||
|
||||
async def find_by_status(self, status: str) -> List[AuditLog]:
|
||||
async def find_by_status(self, status: str) -> List[Any]:
|
||||
"""
|
||||
Find auditlogs by status
|
||||
"""
|
||||
@ -582,7 +583,7 @@ class AuditLogService:
|
||||
getattr(AuditLog, "status") == status
|
||||
).all()
|
||||
|
||||
async def find_by_error_message(self, error_message: str) -> List[AuditLog]:
|
||||
async def find_by_error_message(self, error_message: str) -> List[Any]:
|
||||
"""
|
||||
Find auditlogs by error_message
|
||||
"""
|
||||
@ -590,7 +591,7 @@ class AuditLogService:
|
||||
getattr(AuditLog, "error_message") == error_message
|
||||
).all()
|
||||
|
||||
async def find_by_metadata(self, metadata: Dict[str, Any]) -> List[AuditLog]:
|
||||
async def find_by_metadata(self, metadata: Dict[str, Any]) -> List[Any]:
|
||||
"""
|
||||
Find auditlogs by metadata
|
||||
"""
|
||||
@ -598,7 +599,7 @@ class AuditLogService:
|
||||
getattr(AuditLog, "metadata") == metadata
|
||||
).all()
|
||||
|
||||
async def find_by_phi_accessed(self, phi_accessed: bool) -> List[AuditLog]:
|
||||
async def find_by_phi_accessed(self, phi_accessed: bool) -> List[Any]:
|
||||
"""
|
||||
Find auditlogs by phi_accessed
|
||||
"""
|
||||
@ -606,7 +607,7 @@ class AuditLogService:
|
||||
getattr(AuditLog, "phi_accessed") == phi_accessed
|
||||
).all()
|
||||
|
||||
async def find_by_compliance_flag(self, compliance_flag: bool) -> List[AuditLog]:
|
||||
async def find_by_compliance_flag(self, compliance_flag: bool) -> List[Any]:
|
||||
"""
|
||||
Find auditlogs by compliance_flag
|
||||
"""
|
||||
@ -614,7 +615,7 @@ class AuditLogService:
|
||||
getattr(AuditLog, "compliance_flag") == compliance_flag
|
||||
).all()
|
||||
|
||||
async def find_by_created_at(self, created_at: Any) -> List[AuditLog]:
|
||||
async def find_by_created_at(self, created_at: Any) -> List[Any]:
|
||||
"""
|
||||
Find auditlogs by created_at
|
||||
"""
|
||||
@ -623,7 +624,7 @@ class AuditLogService:
|
||||
).all()
|
||||
|
||||
# =========== Relationship Methods ===========
|
||||
async def get_by_user_id(self, audit_log_id: UUID) -> User:
|
||||
async def get_by_user_id(self, audit_log_id: UUID) -> Any:
|
||||
"""
|
||||
Get the user for this auditlog
|
||||
"""
|
||||
@ -1,7 +1,8 @@
|
||||
from datetime import date, datetime
|
||||
"""
|
||||
ClaimReview Service Layer
|
||||
Enterprise-grade service with business logic, validation, and error handling
|
||||
Architecture: Routers → Services/CRUD → SQLAlchemy Models + Pydantic Schemas
|
||||
Architecture: Any → Services/CRUD → SQLAlchemy Models + Pydantic Schemas
|
||||
"""
|
||||
from typing import List, Optional, Tuple, Dict, Any
|
||||
from uuid import UUID
|
||||
@ -14,7 +15,7 @@ from src.validation.claim_review_schemas import ClaimReviewCreate, ClaimReviewUp
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
class ClaimReviewService:
|
||||
class ClaimReviewCRUD:
|
||||
"""
|
||||
Service class for ClaimReview business logic.
|
||||
|
||||
@ -22,7 +23,7 @@ class ClaimReviewService:
|
||||
and complex queries.
|
||||
"""
|
||||
|
||||
def __init__(self, db: Session):
|
||||
def __init__(self, db: Any):
|
||||
"""Initialize service with database session."""
|
||||
self.db = db
|
||||
|
||||
@ -38,11 +39,11 @@ class ClaimReviewService:
|
||||
Get all claimreviews with pagination and filtering.
|
||||
|
||||
Args:
|
||||
skip: Number of records to skip
|
||||
limit: Maximum records to return
|
||||
filters: Dictionary of field filters
|
||||
order_by: Field to order by
|
||||
order_desc: Order descending if True
|
||||
skip: Any of records to skip
|
||||
limit: Any records to return
|
||||
filters: Any of field filters
|
||||
order_by: Any to order by
|
||||
order_desc: Any descending if True
|
||||
|
||||
Returns:
|
||||
Tuple of (list of claimreviews, total count)
|
||||
@ -85,7 +86,7 @@ class ClaimReviewService:
|
||||
Get a specific claimreview by ID.
|
||||
|
||||
Args:
|
||||
claim_review_id: The UUID of the claimreview
|
||||
claim_review_id: Any UUID of the claimreview
|
||||
|
||||
Returns:
|
||||
The claimreview if found, None otherwise
|
||||
@ -95,12 +96,12 @@ class ClaimReviewService:
|
||||
ClaimReview.id == claim_review_id
|
||||
).first()
|
||||
|
||||
async def create(self, claim_review_in: ClaimReviewCreate) -> ClaimReview:
|
||||
async def create(self, claim_review_in: Any) -> Any:
|
||||
"""
|
||||
Create a new claimreview.
|
||||
|
||||
Args:
|
||||
claim_review_in: The claimreview data to create
|
||||
claim_review_in: Any claimreview data to create
|
||||
|
||||
Returns:
|
||||
The created claimreview
|
||||
@ -125,14 +126,14 @@ class ClaimReviewService:
|
||||
async def update(
|
||||
self,
|
||||
claim_review_id: UUID,
|
||||
claim_review_in: ClaimReviewUpdate
|
||||
claim_review_in: Any
|
||||
) -> Optional[ClaimReview]:
|
||||
"""
|
||||
Update an existing claimreview.
|
||||
|
||||
Args:
|
||||
claim_review_id: The UUID of the claimreview to update
|
||||
claim_review_in: The updated claimreview data
|
||||
claim_review_id: Any UUID of the claimreview to update
|
||||
claim_review_in: Any updated claimreview data
|
||||
|
||||
Returns:
|
||||
The updated claimreview if found, None otherwise
|
||||
@ -163,7 +164,7 @@ class ClaimReviewService:
|
||||
Delete a claimreview.
|
||||
|
||||
Args:
|
||||
claim_review_id: The UUID of the claimreview to delete
|
||||
claim_review_id: Any UUID of the claimreview to delete
|
||||
|
||||
Returns:
|
||||
True if deleted, False if not found
|
||||
@ -190,9 +191,9 @@ class ClaimReviewService:
|
||||
Get all claimreviews for a specific Claim.
|
||||
|
||||
Args:
|
||||
claim_id: The UUID of the Claim
|
||||
skip: Number of records to skip
|
||||
limit: Maximum records to return
|
||||
claim_id: Any UUID of the Claim
|
||||
skip: Any of records to skip
|
||||
limit: Any records to return
|
||||
|
||||
Returns:
|
||||
Tuple of (list of claimreviews, total count)
|
||||
@ -216,9 +217,9 @@ class ClaimReviewService:
|
||||
Get all claimreviews for a specific User.
|
||||
|
||||
Args:
|
||||
user_id: The UUID of the User
|
||||
skip: Number of records to skip
|
||||
limit: Maximum records to return
|
||||
user_id: Any UUID of the User
|
||||
skip: Any of records to skip
|
||||
limit: Any records to return
|
||||
|
||||
Returns:
|
||||
Tuple of (list of claimreviews, total count)
|
||||
@ -242,9 +243,9 @@ class ClaimReviewService:
|
||||
Get all claimreviews for a specific User.
|
||||
|
||||
Args:
|
||||
user_id: The UUID of the User
|
||||
skip: Number of records to skip
|
||||
limit: Maximum records to return
|
||||
user_id: Any UUID of the User
|
||||
skip: Any of records to skip
|
||||
limit: Any records to return
|
||||
|
||||
Returns:
|
||||
Tuple of (list of claimreviews, total count)
|
||||
@ -327,7 +328,7 @@ class ClaimReviewService:
|
||||
await event_bus.emit("review.completed", event_data)
|
||||
|
||||
# =========== Custom Service Methods ===========
|
||||
async def find_one(self, _id: UUID) -> ClaimReview:
|
||||
async def find_one(self, _id: UUID) -> Any:
|
||||
"""
|
||||
Get review by ID
|
||||
GET /api/v1/reviews/{id}
|
||||
@ -335,7 +336,7 @@ class ClaimReviewService:
|
||||
# Custom method implementation
|
||||
raise NotImplementedError(f"Method find_one not yet implemented")
|
||||
|
||||
async def approve(self, _id: UUID, notes: Any, approved_codes: Any) -> ClaimReview:
|
||||
async def approve(self, _id: UUID, notes: Any, approved_codes: Any) -> Any:
|
||||
"""
|
||||
Approve review
|
||||
POST /api/v1/reviews/{id}/approve
|
||||
@ -370,7 +371,7 @@ class ClaimReviewService:
|
||||
|
||||
return claim_review
|
||||
|
||||
async def reject(self, _id: UUID, reason: Any, notes: Any, corrective_actions: Any) -> ClaimReview:
|
||||
async def reject(self, _id: UUID, reason: Any, notes: Any, corrective_actions: Any) -> Any:
|
||||
"""
|
||||
Reject review
|
||||
POST /api/v1/reviews/{id}/reject
|
||||
@ -398,7 +399,7 @@ class ClaimReviewService:
|
||||
|
||||
return claim_review
|
||||
|
||||
async def escalate(self, _id: UUID, escalate_to: Any, reason: Any) -> ClaimReview:
|
||||
async def escalate(self, _id: UUID, escalate_to: Any, reason: Any) -> Any:
|
||||
"""
|
||||
Escalate review
|
||||
POST /api/v1/reviews/{id}/escalate
|
||||
@ -436,7 +437,7 @@ class ClaimReviewService:
|
||||
|
||||
return claim_review
|
||||
|
||||
async def get_queue(self, assigned_to: Any, priority: Any) -> List[ClaimReview]:
|
||||
async def get_queue(self, assigned_to: Any, priority: Any) -> List[Any]:
|
||||
"""
|
||||
Get review queue
|
||||
GET /api/v1/reviews/queue
|
||||
@ -444,7 +445,7 @@ class ClaimReviewService:
|
||||
# Custom method implementation
|
||||
raise NotImplementedError(f"Method get_queue not yet implemented")
|
||||
|
||||
async def findByReviewer(self, reviewer_id: Any) -> ClaimReview:
|
||||
async def findByReviewer(self, reviewer_id: Any) -> Any:
|
||||
"""
|
||||
Get reviews by reviewer
|
||||
custom
|
||||
@ -455,7 +456,7 @@ class ClaimReviewService:
|
||||
reviews = result.scalars().all()
|
||||
return reviews
|
||||
|
||||
async def findPendingReviews(self, skip: Any = 0, take: Any = 10) -> ClaimReview:
|
||||
async def findPendingReviews(self, skip: Any = 0, take: Any = 10) -> Any:
|
||||
"""
|
||||
Get pending reviews
|
||||
custom
|
||||
@ -471,7 +472,7 @@ class ClaimReviewService:
|
||||
return claim_reviews
|
||||
|
||||
# =========== Query Methods (findBy*) ===========
|
||||
async def find_by_review_status(self, review_status: str) -> List[ClaimReview]:
|
||||
async def find_by_review_status(self, review_status: str) -> List[Any]:
|
||||
"""
|
||||
Find claimreviews by review_status
|
||||
"""
|
||||
@ -479,7 +480,7 @@ class ClaimReviewService:
|
||||
getattr(ClaimReview, "review_status") == review_status
|
||||
).all()
|
||||
|
||||
async def find_by_review_type(self, review_type: str) -> List[ClaimReview]:
|
||||
async def find_by_review_type(self, review_type: str) -> List[Any]:
|
||||
"""
|
||||
Find claimreviews by review_type
|
||||
"""
|
||||
@ -487,7 +488,7 @@ class ClaimReviewService:
|
||||
getattr(ClaimReview, "review_type") == review_type
|
||||
).all()
|
||||
|
||||
async def find_by_confidence_threshold_triggered(self, confidence_threshold_triggered: bool) -> List[ClaimReview]:
|
||||
async def find_by_confidence_threshold_triggered(self, confidence_threshold_triggered: bool) -> List[Any]:
|
||||
"""
|
||||
Find claimreviews by confidence_threshold_triggered
|
||||
"""
|
||||
@ -495,7 +496,7 @@ class ClaimReviewService:
|
||||
getattr(ClaimReview, "confidence_threshold_triggered") == confidence_threshold_triggered
|
||||
).all()
|
||||
|
||||
async def find_by_original_icd10_codes(self, original_icd10_codes: Dict[str, Any]) -> List[ClaimReview]:
|
||||
async def find_by_original_icd10_codes(self, original_icd10_codes: Dict[str, Any]) -> List[Any]:
|
||||
"""
|
||||
Find claimreviews by original_icd10_codes
|
||||
"""
|
||||
@ -503,7 +504,7 @@ class ClaimReviewService:
|
||||
getattr(ClaimReview, "original_icd10_codes") == original_icd10_codes
|
||||
).all()
|
||||
|
||||
async def find_by_original_cpt_codes(self, original_cpt_codes: Dict[str, Any]) -> List[ClaimReview]:
|
||||
async def find_by_original_cpt_codes(self, original_cpt_codes: Dict[str, Any]) -> List[Any]:
|
||||
"""
|
||||
Find claimreviews by original_cpt_codes
|
||||
"""
|
||||
@ -511,7 +512,7 @@ class ClaimReviewService:
|
||||
getattr(ClaimReview, "original_cpt_codes") == original_cpt_codes
|
||||
).all()
|
||||
|
||||
async def find_by_revised_icd10_codes(self, revised_icd10_codes: Dict[str, Any]) -> List[ClaimReview]:
|
||||
async def find_by_revised_icd10_codes(self, revised_icd10_codes: Dict[str, Any]) -> List[Any]:
|
||||
"""
|
||||
Find claimreviews by revised_icd10_codes
|
||||
"""
|
||||
@ -519,7 +520,7 @@ class ClaimReviewService:
|
||||
getattr(ClaimReview, "revised_icd10_codes") == revised_icd10_codes
|
||||
).all()
|
||||
|
||||
async def find_by_revised_cpt_codes(self, revised_cpt_codes: Dict[str, Any]) -> List[ClaimReview]:
|
||||
async def find_by_revised_cpt_codes(self, revised_cpt_codes: Dict[str, Any]) -> List[Any]:
|
||||
"""
|
||||
Find claimreviews by revised_cpt_codes
|
||||
"""
|
||||
@ -527,7 +528,7 @@ class ClaimReviewService:
|
||||
getattr(ClaimReview, "revised_cpt_codes") == revised_cpt_codes
|
||||
).all()
|
||||
|
||||
async def find_by_reviewer_notes(self, reviewer_notes: str) -> List[ClaimReview]:
|
||||
async def find_by_reviewer_notes(self, reviewer_notes: str) -> List[Any]:
|
||||
"""
|
||||
Find claimreviews by reviewer_notes
|
||||
"""
|
||||
@ -535,7 +536,7 @@ class ClaimReviewService:
|
||||
getattr(ClaimReview, "reviewer_notes") == reviewer_notes
|
||||
).all()
|
||||
|
||||
async def find_by_flagged_issues(self, flagged_issues: Dict[str, Any]) -> List[ClaimReview]:
|
||||
async def find_by_flagged_issues(self, flagged_issues: Dict[str, Any]) -> List[Any]:
|
||||
"""
|
||||
Find claimreviews by flagged_issues
|
||||
"""
|
||||
@ -543,7 +544,7 @@ class ClaimReviewService:
|
||||
getattr(ClaimReview, "flagged_issues") == flagged_issues
|
||||
).all()
|
||||
|
||||
async def find_by_corrective_actions(self, corrective_actions: Dict[str, Any]) -> List[ClaimReview]:
|
||||
async def find_by_corrective_actions(self, corrective_actions: Dict[str, Any]) -> List[Any]:
|
||||
"""
|
||||
Find claimreviews by corrective_actions
|
||||
"""
|
||||
@ -551,7 +552,7 @@ class ClaimReviewService:
|
||||
getattr(ClaimReview, "corrective_actions") == corrective_actions
|
||||
).all()
|
||||
|
||||
async def find_by_review_duration_seconds(self, review_duration_seconds: int) -> List[ClaimReview]:
|
||||
async def find_by_review_duration_seconds(self, review_duration_seconds: int) -> List[Any]:
|
||||
"""
|
||||
Find claimreviews by review_duration_seconds
|
||||
"""
|
||||
@ -559,7 +560,7 @@ class ClaimReviewService:
|
||||
getattr(ClaimReview, "review_duration_seconds") == review_duration_seconds
|
||||
).all()
|
||||
|
||||
async def find_by_escalation_reason(self, escalation_reason: str) -> List[ClaimReview]:
|
||||
async def find_by_escalation_reason(self, escalation_reason: str) -> List[Any]:
|
||||
"""
|
||||
Find claimreviews by escalation_reason
|
||||
"""
|
||||
@ -567,7 +568,7 @@ class ClaimReviewService:
|
||||
getattr(ClaimReview, "escalation_reason") == escalation_reason
|
||||
).all()
|
||||
|
||||
async def find_by_escalated_at(self, escalated_at: datetime) -> List[ClaimReview]:
|
||||
async def find_by_escalated_at(self, escalated_at: datetime) -> List[Any]:
|
||||
"""
|
||||
Find claimreviews by escalated_at
|
||||
"""
|
||||
@ -575,7 +576,7 @@ class ClaimReviewService:
|
||||
getattr(ClaimReview, "escalated_at") == escalated_at
|
||||
).all()
|
||||
|
||||
async def find_by_reviewed_at(self, reviewed_at: datetime) -> List[ClaimReview]:
|
||||
async def find_by_reviewed_at(self, reviewed_at: datetime) -> List[Any]:
|
||||
"""
|
||||
Find claimreviews by reviewed_at
|
||||
"""
|
||||
@ -583,7 +584,7 @@ class ClaimReviewService:
|
||||
getattr(ClaimReview, "reviewed_at") == reviewed_at
|
||||
).all()
|
||||
|
||||
async def find_by_created_at(self, created_at: Any) -> List[ClaimReview]:
|
||||
async def find_by_created_at(self, created_at: Any) -> List[Any]:
|
||||
"""
|
||||
Find claimreviews by created_at
|
||||
"""
|
||||
@ -591,7 +592,7 @@ class ClaimReviewService:
|
||||
getattr(ClaimReview, "created_at") == created_at
|
||||
).all()
|
||||
|
||||
async def find_by_updated_at(self, updated_at: Any) -> List[ClaimReview]:
|
||||
async def find_by_updated_at(self, updated_at: Any) -> List[Any]:
|
||||
"""
|
||||
Find claimreviews by updated_at
|
||||
"""
|
||||
@ -600,7 +601,7 @@ class ClaimReviewService:
|
||||
).all()
|
||||
|
||||
# =========== Relationship Methods ===========
|
||||
async def get_by_claim_id(self, claim_review_id: UUID) -> Claim:
|
||||
async def get_by_claim_id(self, claim_review_id: UUID) -> Any:
|
||||
"""
|
||||
Get the claim for this claimreview
|
||||
"""
|
||||
@ -615,7 +616,7 @@ class ClaimReviewService:
|
||||
).first()
|
||||
return None
|
||||
|
||||
async def get_by_reviewer_id(self, claim_review_id: UUID) -> User:
|
||||
async def get_by_reviewer_id(self, claim_review_id: UUID) -> Any:
|
||||
"""
|
||||
Get the user for this claimreview
|
||||
"""
|
||||
@ -630,7 +631,7 @@ class ClaimReviewService:
|
||||
).first()
|
||||
return None
|
||||
|
||||
async def get_by_escalated_to_id(self, claim_review_id: UUID) -> User:
|
||||
async def get_by_escalated_to_id(self, claim_review_id: UUID) -> Any:
|
||||
"""
|
||||
Get the user for this claimreview
|
||||
"""
|
||||
@ -1,7 +1,8 @@
|
||||
from datetime import date, datetime
|
||||
"""
|
||||
ClaimScrubResult Service Layer
|
||||
Enterprise-grade service with business logic, validation, and error handling
|
||||
Architecture: Routers → Services/CRUD → SQLAlchemy Models + Pydantic Schemas
|
||||
Architecture: Any → Services/CRUD → SQLAlchemy Models + Pydantic Schemas
|
||||
"""
|
||||
from typing import List, Optional, Tuple, Dict, Any
|
||||
from uuid import UUID
|
||||
@ -14,7 +15,7 @@ from src.validation.claim_scrub_result_schemas import ClaimScrubResultCreate, Cl
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
class ClaimScrubResultService:
|
||||
class ClaimScrubResultCRUD:
|
||||
"""
|
||||
Service class for ClaimScrubResult business logic.
|
||||
|
||||
@ -22,7 +23,7 @@ class ClaimScrubResultService:
|
||||
and complex queries.
|
||||
"""
|
||||
|
||||
def __init__(self, db: Session):
|
||||
def __init__(self, db: Any):
|
||||
"""Initialize service with database session."""
|
||||
self.db = db
|
||||
|
||||
@ -38,11 +39,11 @@ class ClaimScrubResultService:
|
||||
Get all claimscrubresults with pagination and filtering.
|
||||
|
||||
Args:
|
||||
skip: Number of records to skip
|
||||
limit: Maximum records to return
|
||||
filters: Dictionary of field filters
|
||||
order_by: Field to order by
|
||||
order_desc: Order descending if True
|
||||
skip: Any of records to skip
|
||||
limit: Any records to return
|
||||
filters: Any of field filters
|
||||
order_by: Any to order by
|
||||
order_desc: Any descending if True
|
||||
|
||||
Returns:
|
||||
Tuple of (list of claimscrubresults, total count)
|
||||
@ -85,7 +86,7 @@ class ClaimScrubResultService:
|
||||
Get a specific claimscrubresult by ID.
|
||||
|
||||
Args:
|
||||
claim_scrub_result_id: The UUID of the claimscrubresult
|
||||
claim_scrub_result_id: Any UUID of the claimscrubresult
|
||||
|
||||
Returns:
|
||||
The claimscrubresult if found, None otherwise
|
||||
@ -95,12 +96,12 @@ class ClaimScrubResultService:
|
||||
ClaimScrubResult.id == claim_scrub_result_id
|
||||
).first()
|
||||
|
||||
async def create(self, claim_scrub_result_in: ClaimScrubResultCreate) -> ClaimScrubResult:
|
||||
async def create(self, claim_scrub_result_in: Any) -> Any:
|
||||
"""
|
||||
Create a new claimscrubresult.
|
||||
|
||||
Args:
|
||||
claim_scrub_result_in: The claimscrubresult data to create
|
||||
claim_scrub_result_in: Any claimscrubresult data to create
|
||||
|
||||
Returns:
|
||||
The created claimscrubresult
|
||||
@ -130,14 +131,14 @@ class ClaimScrubResultService:
|
||||
async def update(
|
||||
self,
|
||||
claim_scrub_result_id: UUID,
|
||||
claim_scrub_result_in: ClaimScrubResultUpdate
|
||||
claim_scrub_result_in: Any
|
||||
) -> Optional[ClaimScrubResult]:
|
||||
"""
|
||||
Update an existing claimscrubresult.
|
||||
|
||||
Args:
|
||||
claim_scrub_result_id: The UUID of the claimscrubresult to update
|
||||
claim_scrub_result_in: The updated claimscrubresult data
|
||||
claim_scrub_result_id: Any UUID of the claimscrubresult to update
|
||||
claim_scrub_result_in: Any updated claimscrubresult data
|
||||
|
||||
Returns:
|
||||
The updated claimscrubresult if found, None otherwise
|
||||
@ -168,7 +169,7 @@ class ClaimScrubResultService:
|
||||
Delete a claimscrubresult.
|
||||
|
||||
Args:
|
||||
claim_scrub_result_id: The UUID of the claimscrubresult to delete
|
||||
claim_scrub_result_id: Any UUID of the claimscrubresult to delete
|
||||
|
||||
Returns:
|
||||
True if deleted, False if not found
|
||||
@ -195,9 +196,9 @@ class ClaimScrubResultService:
|
||||
Get all claimscrubresults for a specific Claim.
|
||||
|
||||
Args:
|
||||
claim_id: The UUID of the Claim
|
||||
skip: Number of records to skip
|
||||
limit: Maximum records to return
|
||||
claim_id: Any UUID of the Claim
|
||||
skip: Any of records to skip
|
||||
limit: Any records to return
|
||||
|
||||
Returns:
|
||||
Tuple of (list of claimscrubresults, total count)
|
||||
@ -212,7 +213,7 @@ class ClaimScrubResultService:
|
||||
return items, total
|
||||
|
||||
# =========== BLS Business Rules ===========
|
||||
async def scrubClaimWithRAG(self, claim_scrub_result_in: ClaimScrubResultCreate, existing: Optional[ClaimScrubResult] = None) -> Any:
|
||||
async def scrubClaimWithRAG(self, claim_scrub_result_in: Any, existing: Optional[ClaimScrubResult] = None) -> Any:
|
||||
"""
|
||||
Scrub claims against payer rules using RAG
|
||||
@generated from DSL function
|
||||
@ -261,7 +262,7 @@ class ClaimScrubResultService:
|
||||
claimScrubResult.requires_manual_review = scrubResult.requires_manual_review
|
||||
claimScrubResult.review_priority = scrubResult.review_priority
|
||||
|
||||
async def validateNCCIEdits(self, claim_scrub_result_in: ClaimScrubResultCreate, existing: Optional[ClaimScrubResult] = None) -> Any:
|
||||
async def validateNCCIEdits(self, claim_scrub_result_in: Any, existing: Optional[ClaimScrubResult] = None) -> Any:
|
||||
"""
|
||||
Validate claims against NCCI edits
|
||||
@generated from DSL function
|
||||
@ -310,7 +311,7 @@ class ClaimScrubResultService:
|
||||
if len(ncci_violations) > 0:
|
||||
claim_scrub_result.failed_checks = claim_scrub_result.failed_checks + len(ncci_violations)
|
||||
|
||||
async def validateCoverageDeterminations(self, claim_scrub_result_in: ClaimScrubResultCreate, existing: Optional[ClaimScrubResult] = None) -> Any:
|
||||
async def validateCoverageDeterminations(self, claim_scrub_result_in: Any, existing: Optional[ClaimScrubResult] = None) -> Any:
|
||||
"""
|
||||
Validate against LCD/NCD coverage determinations
|
||||
@generated from DSL function
|
||||
@ -375,7 +376,7 @@ class ClaimScrubResultService:
|
||||
claim_scrub_result.requires_manual_review = True
|
||||
claim_scrub_result.overall_risk_level = "HIGH"
|
||||
|
||||
async def flagFailures(self, claim_scrub_result_in: ClaimScrubResultCreate, existing: Optional[ClaimScrubResult] = None) -> Any:
|
||||
async def flagFailures(self, claim_scrub_result_in: Any, existing: Optional[ClaimScrubResult] = None) -> Any:
|
||||
"""
|
||||
Flag claim failures with corrective actions
|
||||
@generated from DSL function
|
||||
@ -464,7 +465,7 @@ class ClaimScrubResultService:
|
||||
await event_bus.emit("claim.scrubbed", event_data)
|
||||
|
||||
# =========== Custom Service Methods ===========
|
||||
async def scrub_claim(self, _in: Create) -> ClaimScrubResult:
|
||||
async def scrub_claim(self, _in: Any) -> Any:
|
||||
"""
|
||||
Scrub claim against rules
|
||||
POST /api/v1/claims/scrub
|
||||
@ -472,7 +473,7 @@ class ClaimScrubResultService:
|
||||
# Custom method implementation
|
||||
raise NotImplementedError(f"Method scrub_claim not yet implemented")
|
||||
|
||||
async def get_scrub_result(self, _id: UUID) -> ClaimScrubResult:
|
||||
async def get_scrub_result(self, _id: UUID) -> Any:
|
||||
"""
|
||||
Get scrub result
|
||||
GET /api/v1/claims/scrub/{id}
|
||||
@ -480,7 +481,7 @@ class ClaimScrubResultService:
|
||||
# Custom method implementation
|
||||
raise NotImplementedError(f"Method get_scrub_result not yet implemented")
|
||||
|
||||
async def rerun_scrub(self, _id: UUID) -> ClaimScrubResult:
|
||||
async def rerun_scrub(self, _id: UUID) -> Any:
|
||||
"""
|
||||
Rerun claim scrubbing
|
||||
POST /api/v1/claims/scrub/{id}/rerun
|
||||
@ -488,7 +489,7 @@ class ClaimScrubResultService:
|
||||
# Custom method implementation
|
||||
raise NotImplementedError(f"Method rerun_scrub not yet implemented")
|
||||
|
||||
async def validate_ncci(self, _in: Create) -> ClaimScrubResult:
|
||||
async def validate_ncci(self, _in: Any) -> Any:
|
||||
"""
|
||||
Validate NCCI edits
|
||||
POST /api/v1/claims/validate/ncci
|
||||
@ -496,7 +497,7 @@ class ClaimScrubResultService:
|
||||
# Custom method implementation
|
||||
raise NotImplementedError(f"Method validate_ncci not yet implemented")
|
||||
|
||||
async def validate_lcd(self, _in: Create) -> ClaimScrubResult:
|
||||
async def validate_lcd(self, _in: Any) -> Any:
|
||||
"""
|
||||
Validate LCD coverage
|
||||
POST /api/v1/claims/validate/lcd
|
||||
@ -504,7 +505,7 @@ class ClaimScrubResultService:
|
||||
# Custom method implementation
|
||||
raise NotImplementedError(f"Method validate_lcd not yet implemented")
|
||||
|
||||
async def validate_ncd(self, _in: Create) -> ClaimScrubResult:
|
||||
async def validate_ncd(self, _in: Any) -> Any:
|
||||
"""
|
||||
Validate NCD coverage
|
||||
POST /api/v1/claims/validate/ncd
|
||||
@ -512,7 +513,7 @@ class ClaimScrubResultService:
|
||||
# Custom method implementation
|
||||
raise NotImplementedError(f"Method validate_ncd not yet implemented")
|
||||
|
||||
async def get_failures(self, query_params: Optional[Dict[str, Any]] = None) -> List[ClaimScrubResult]:
|
||||
async def get_failures(self, query_params: Optional[Dict[str, Any]] = None) -> List[Any]:
|
||||
"""
|
||||
Get scrub failures
|
||||
GET /api/v1/claims/scrub/failures
|
||||
@ -520,7 +521,7 @@ class ClaimScrubResultService:
|
||||
# Custom method implementation
|
||||
raise NotImplementedError(f"Method get_failures not yet implemented")
|
||||
|
||||
async def scrubClaim(self, claim_id: Any, payer_id: Any, icd10_codes: Any, cpt_codes: Any, modifiers: Any) -> ClaimScrubResult:
|
||||
async def scrubClaim(self, claim_id: Any, payer_id: Any, icd10_codes: Any, cpt_codes: Any, modifiers: Any) -> Any:
|
||||
"""
|
||||
Scrub claim
|
||||
custom
|
||||
@ -693,7 +694,7 @@ class ClaimScrubResultService:
|
||||
"modifier_issues": scrub_result.modifier_issues
|
||||
}
|
||||
|
||||
async def validateNCCI(self, cpt_codes: Any, modifiers: Any) -> ClaimScrubResult:
|
||||
async def validateNCCI(self, cpt_codes: Any, modifiers: Any) -> Any:
|
||||
"""
|
||||
Validate NCCI edits
|
||||
custom
|
||||
@ -826,7 +827,7 @@ class ClaimScrubResultService:
|
||||
ncci_valid_modifiers = ["25", "59", "XE", "XP", "XS", "XU", "91"]
|
||||
return modifier in ncci_valid_modifiers
|
||||
|
||||
async def validateLCD(self, icd10_codes: Any, cpt_codes: Any, payer_id: Any, state: Any) -> ClaimScrubResult:
|
||||
async def validateLCD(self, icd10_codes: Any, cpt_codes: Any, payer_id: Any, state: Any) -> Any:
|
||||
"""
|
||||
Validate LCD
|
||||
custom
|
||||
@ -838,8 +839,8 @@ class ClaimScrubResultService:
|
||||
Args:
|
||||
icd10_codes: List of ICD-10 diagnosis codes
|
||||
cpt_codes: List of CPT procedure codes
|
||||
payer_idValue: Payer identifier
|
||||
stateValue: State code for LCD jurisdiction
|
||||
payer_idValue: Any identifier
|
||||
stateValue: Any code for LCD jurisdiction
|
||||
|
||||
Returns:
|
||||
Dictionary containing LCD validation results
|
||||
@ -925,7 +926,7 @@ class ClaimScrubResultService:
|
||||
}
|
||||
}
|
||||
|
||||
async def validateNCD(self, icd10_codes: Any, cpt_codes: Any, payer_id: Any) -> ClaimScrubResult:
|
||||
async def validateNCD(self, icd10_codes: Any, cpt_codes: Any, payer_id: Any) -> Any:
|
||||
"""
|
||||
Validate NCD
|
||||
custom
|
||||
@ -937,7 +938,7 @@ class ClaimScrubResultService:
|
||||
Args:
|
||||
icd10_codes: List of ICD-10 diagnosis codes
|
||||
cpt_codes: List of CPT procedure codes
|
||||
payer_idValue: Payer identifier
|
||||
payer_idValue: Any identifier
|
||||
|
||||
Returns:
|
||||
Dictionary containing NCD validation results
|
||||
@ -1034,7 +1035,7 @@ class ClaimScrubResultService:
|
||||
"payer_idValue": payer_idValue
|
||||
}
|
||||
|
||||
async def checkPayerRules(self, payer_id: Any, codes: Any) -> ClaimScrubResult:
|
||||
async def checkPayerRules(self, payer_id: Any, codes: Any) -> Any:
|
||||
"""
|
||||
Check payer rules
|
||||
custom
|
||||
@ -1044,8 +1045,8 @@ class ClaimScrubResultService:
|
||||
Check payer rules for given payer and codes
|
||||
|
||||
Args:
|
||||
payer_id: The payer identifier
|
||||
codes: Dictionary containing procedure codes, diagnosis codes, etc.
|
||||
payer_id: Any payer identifier
|
||||
codes: Any containing procedure codes, diagnosis codes, etc.
|
||||
|
||||
Returns:
|
||||
List of payer rule violations found
|
||||
@ -1135,7 +1136,7 @@ class ClaimScrubResultService:
|
||||
return violations
|
||||
|
||||
# =========== Query Methods (findBy*) ===========
|
||||
async def find_by_scrub_status(self, scrub_status: str) -> List[ClaimScrubResult]:
|
||||
async def find_by_scrub_status(self, scrub_status: str) -> List[Any]:
|
||||
"""
|
||||
Find claimscrubresults by scrub_status
|
||||
"""
|
||||
@ -1143,7 +1144,7 @@ class ClaimScrubResultService:
|
||||
getattr(ClaimScrubResult, "scrub_status") == scrub_status
|
||||
).all()
|
||||
|
||||
async def find_by_overall_risk_level(self, overall_risk_level: str) -> List[ClaimScrubResult]:
|
||||
async def find_by_overall_risk_level(self, overall_risk_level: str) -> List[Any]:
|
||||
"""
|
||||
Find claimscrubresults by overall_risk_level
|
||||
"""
|
||||
@ -1151,7 +1152,7 @@ class ClaimScrubResultService:
|
||||
getattr(ClaimScrubResult, "overall_risk_level") == overall_risk_level
|
||||
).all()
|
||||
|
||||
async def find_by_total_checks(self, total_checks: int) -> List[ClaimScrubResult]:
|
||||
async def find_by_total_checks(self, total_checks: int) -> List[Any]:
|
||||
"""
|
||||
Find claimscrubresults by total_checks
|
||||
"""
|
||||
@ -1159,7 +1160,7 @@ class ClaimScrubResultService:
|
||||
getattr(ClaimScrubResult, "total_checks") == total_checks
|
||||
).all()
|
||||
|
||||
async def find_by_passed_checks(self, passed_checks: int) -> List[ClaimScrubResult]:
|
||||
async def find_by_passed_checks(self, passed_checks: int) -> List[Any]:
|
||||
"""
|
||||
Find claimscrubresults by passed_checks
|
||||
"""
|
||||
@ -1167,7 +1168,7 @@ class ClaimScrubResultService:
|
||||
getattr(ClaimScrubResult, "passed_checks") == passed_checks
|
||||
).all()
|
||||
|
||||
async def find_by_failed_checks(self, failed_checks: int) -> List[ClaimScrubResult]:
|
||||
async def find_by_failed_checks(self, failed_checks: int) -> List[Any]:
|
||||
"""
|
||||
Find claimscrubresults by failed_checks
|
||||
"""
|
||||
@ -1175,7 +1176,7 @@ class ClaimScrubResultService:
|
||||
getattr(ClaimScrubResult, "failed_checks") == failed_checks
|
||||
).all()
|
||||
|
||||
async def find_by_warning_checks(self, warning_checks: int) -> List[ClaimScrubResult]:
|
||||
async def find_by_warning_checks(self, warning_checks: int) -> List[Any]:
|
||||
"""
|
||||
Find claimscrubresults by warning_checks
|
||||
"""
|
||||
@ -1183,7 +1184,7 @@ class ClaimScrubResultService:
|
||||
getattr(ClaimScrubResult, "warning_checks") == warning_checks
|
||||
).all()
|
||||
|
||||
async def find_by_ncci_violations(self, ncci_violations: Dict[str, Any]) -> List[ClaimScrubResult]:
|
||||
async def find_by_ncci_violations(self, ncci_violations: Dict[str, Any]) -> List[Any]:
|
||||
"""
|
||||
Find claimscrubresults by ncci_violations
|
||||
"""
|
||||
@ -1191,7 +1192,7 @@ class ClaimScrubResultService:
|
||||
getattr(ClaimScrubResult, "ncci_violations") == ncci_violations
|
||||
).all()
|
||||
|
||||
async def find_by_lcd_violations(self, lcd_violations: Dict[str, Any]) -> List[ClaimScrubResult]:
|
||||
async def find_by_lcd_violations(self, lcd_violations: Dict[str, Any]) -> List[Any]:
|
||||
"""
|
||||
Find claimscrubresults by lcd_violations
|
||||
"""
|
||||
@ -1199,7 +1200,7 @@ class ClaimScrubResultService:
|
||||
getattr(ClaimScrubResult, "lcd_violations") == lcd_violations
|
||||
).all()
|
||||
|
||||
async def find_by_ncd_violations(self, ncd_violations: Dict[str, Any]) -> List[ClaimScrubResult]:
|
||||
async def find_by_ncd_violations(self, ncd_violations: Dict[str, Any]) -> List[Any]:
|
||||
"""
|
||||
Find claimscrubresults by ncd_violations
|
||||
"""
|
||||
@ -1207,7 +1208,7 @@ class ClaimScrubResultService:
|
||||
getattr(ClaimScrubResult, "ncd_violations") == ncd_violations
|
||||
).all()
|
||||
|
||||
async def find_by_payer_rule_violations(self, payer_rule_violations: Dict[str, Any]) -> List[ClaimScrubResult]:
|
||||
async def find_by_payer_rule_violations(self, payer_rule_violations: Dict[str, Any]) -> List[Any]:
|
||||
"""
|
||||
Find claimscrubresults by payer_rule_violations
|
||||
"""
|
||||
@ -1215,7 +1216,7 @@ class ClaimScrubResultService:
|
||||
getattr(ClaimScrubResult, "payer_rule_violations") == payer_rule_violations
|
||||
).all()
|
||||
|
||||
async def find_by_coding_errors(self, coding_errors: Dict[str, Any]) -> List[ClaimScrubResult]:
|
||||
async def find_by_coding_errors(self, coding_errors: Dict[str, Any]) -> List[Any]:
|
||||
"""
|
||||
Find claimscrubresults by coding_errors
|
||||
"""
|
||||
@ -1223,7 +1224,7 @@ class ClaimScrubResultService:
|
||||
getattr(ClaimScrubResult, "coding_errors") == coding_errors
|
||||
).all()
|
||||
|
||||
async def find_by_medical_necessity_issues(self, medical_necessity_issues: Dict[str, Any]) -> List[ClaimScrubResult]:
|
||||
async def find_by_medical_necessity_issues(self, medical_necessity_issues: Dict[str, Any]) -> List[Any]:
|
||||
"""
|
||||
Find claimscrubresults by medical_necessity_issues
|
||||
"""
|
||||
@ -1231,7 +1232,7 @@ class ClaimScrubResultService:
|
||||
getattr(ClaimScrubResult, "medical_necessity_issues") == medical_necessity_issues
|
||||
).all()
|
||||
|
||||
async def find_by_modifier_issues(self, modifier_issues: Dict[str, Any]) -> List[ClaimScrubResult]:
|
||||
async def find_by_modifier_issues(self, modifier_issues: Dict[str, Any]) -> List[Any]:
|
||||
"""
|
||||
Find claimscrubresults by modifier_issues
|
||||
"""
|
||||
@ -1239,7 +1240,7 @@ class ClaimScrubResultService:
|
||||
getattr(ClaimScrubResult, "modifier_issues") == modifier_issues
|
||||
).all()
|
||||
|
||||
async def find_by_bundling_issues(self, bundling_issues: Dict[str, Any]) -> List[ClaimScrubResult]:
|
||||
async def find_by_bundling_issues(self, bundling_issues: Dict[str, Any]) -> List[Any]:
|
||||
"""
|
||||
Find claimscrubresults by bundling_issues
|
||||
"""
|
||||
@ -1247,7 +1248,7 @@ class ClaimScrubResultService:
|
||||
getattr(ClaimScrubResult, "bundling_issues") == bundling_issues
|
||||
).all()
|
||||
|
||||
async def find_by_denial_risk_patterns(self, denial_risk_patterns: Dict[str, Any]) -> List[ClaimScrubResult]:
|
||||
async def find_by_denial_risk_patterns(self, denial_risk_patterns: Dict[str, Any]) -> List[Any]:
|
||||
"""
|
||||
Find claimscrubresults by denial_risk_patterns
|
||||
"""
|
||||
@ -1255,7 +1256,7 @@ class ClaimScrubResultService:
|
||||
getattr(ClaimScrubResult, "denial_risk_patterns") == denial_risk_patterns
|
||||
).all()
|
||||
|
||||
async def find_by_corrective_actions(self, corrective_actions: Dict[str, Any]) -> List[ClaimScrubResult]:
|
||||
async def find_by_corrective_actions(self, corrective_actions: Dict[str, Any]) -> List[Any]:
|
||||
"""
|
||||
Find claimscrubresults by corrective_actions
|
||||
"""
|
||||
@ -1263,7 +1264,7 @@ class ClaimScrubResultService:
|
||||
getattr(ClaimScrubResult, "corrective_actions") == corrective_actions
|
||||
).all()
|
||||
|
||||
async def find_by_suggested_codes(self, suggested_codes: Dict[str, Any]) -> List[ClaimScrubResult]:
|
||||
async def find_by_suggested_codes(self, suggested_codes: Dict[str, Any]) -> List[Any]:
|
||||
"""
|
||||
Find claimscrubresults by suggested_codes
|
||||
"""
|
||||
@ -1271,7 +1272,7 @@ class ClaimScrubResultService:
|
||||
getattr(ClaimScrubResult, "suggested_codes") == suggested_codes
|
||||
).all()
|
||||
|
||||
async def find_by_rag_documents_used(self, rag_documents_used: Dict[str, Any]) -> List[ClaimScrubResult]:
|
||||
async def find_by_rag_documents_used(self, rag_documents_used: Dict[str, Any]) -> List[Any]:
|
||||
"""
|
||||
Find claimscrubresults by rag_documents_used
|
||||
"""
|
||||
@ -1279,7 +1280,7 @@ class ClaimScrubResultService:
|
||||
getattr(ClaimScrubResult, "rag_documents_used") == rag_documents_used
|
||||
).all()
|
||||
|
||||
async def find_by_scrub_engine_version(self, scrub_engine_version: str) -> List[ClaimScrubResult]:
|
||||
async def find_by_scrub_engine_version(self, scrub_engine_version: str) -> List[Any]:
|
||||
"""
|
||||
Find claimscrubresults by scrub_engine_version
|
||||
"""
|
||||
@ -1287,7 +1288,7 @@ class ClaimScrubResultService:
|
||||
getattr(ClaimScrubResult, "scrub_engine_version") == scrub_engine_version
|
||||
).all()
|
||||
|
||||
async def find_by_processing_time_ms(self, processing_time_ms: int) -> List[ClaimScrubResult]:
|
||||
async def find_by_processing_time_ms(self, processing_time_ms: int) -> List[Any]:
|
||||
"""
|
||||
Find claimscrubresults by processing_time_ms
|
||||
"""
|
||||
@ -1295,7 +1296,7 @@ class ClaimScrubResultService:
|
||||
getattr(ClaimScrubResult, "processing_time_ms") == processing_time_ms
|
||||
).all()
|
||||
|
||||
async def find_by_auto_fix_applied(self, auto_fix_applied: bool) -> List[ClaimScrubResult]:
|
||||
async def find_by_auto_fix_applied(self, auto_fix_applied: bool) -> List[Any]:
|
||||
"""
|
||||
Find claimscrubresults by auto_fix_applied
|
||||
"""
|
||||
@ -1303,7 +1304,7 @@ class ClaimScrubResultService:
|
||||
getattr(ClaimScrubResult, "auto_fix_applied") == auto_fix_applied
|
||||
).all()
|
||||
|
||||
async def find_by_auto_fix_details(self, auto_fix_details: Dict[str, Any]) -> List[ClaimScrubResult]:
|
||||
async def find_by_auto_fix_details(self, auto_fix_details: Dict[str, Any]) -> List[Any]:
|
||||
"""
|
||||
Find claimscrubresults by auto_fix_details
|
||||
"""
|
||||
@ -1311,7 +1312,7 @@ class ClaimScrubResultService:
|
||||
getattr(ClaimScrubResult, "auto_fix_details") == auto_fix_details
|
||||
).all()
|
||||
|
||||
async def find_by_requires_manual_review(self, requires_manual_review: bool) -> List[ClaimScrubResult]:
|
||||
async def find_by_requires_manual_review(self, requires_manual_review: bool) -> List[Any]:
|
||||
"""
|
||||
Find claimscrubresults by requires_manual_review
|
||||
"""
|
||||
@ -1319,7 +1320,7 @@ class ClaimScrubResultService:
|
||||
getattr(ClaimScrubResult, "requires_manual_review") == requires_manual_review
|
||||
).all()
|
||||
|
||||
async def find_by_review_priority(self, review_priority: str) -> List[ClaimScrubResult]:
|
||||
async def find_by_review_priority(self, review_priority: str) -> List[Any]:
|
||||
"""
|
||||
Find claimscrubresults by review_priority
|
||||
"""
|
||||
@ -1327,7 +1328,7 @@ class ClaimScrubResultService:
|
||||
getattr(ClaimScrubResult, "review_priority") == review_priority
|
||||
).all()
|
||||
|
||||
async def find_by_scrubbed_at(self, scrubbed_at: datetime) -> List[ClaimScrubResult]:
|
||||
async def find_by_scrubbed_at(self, scrubbed_at: datetime) -> List[Any]:
|
||||
"""
|
||||
Find claimscrubresults by scrubbed_at
|
||||
"""
|
||||
@ -1335,7 +1336,7 @@ class ClaimScrubResultService:
|
||||
getattr(ClaimScrubResult, "scrubbed_at") == scrubbed_at
|
||||
).all()
|
||||
|
||||
async def find_by_created_at(self, created_at: Any) -> List[ClaimScrubResult]:
|
||||
async def find_by_created_at(self, created_at: Any) -> List[Any]:
|
||||
"""
|
||||
Find claimscrubresults by created_at
|
||||
"""
|
||||
@ -1343,7 +1344,7 @@ class ClaimScrubResultService:
|
||||
getattr(ClaimScrubResult, "created_at") == created_at
|
||||
).all()
|
||||
|
||||
async def find_by_updated_at(self, updated_at: Any) -> List[ClaimScrubResult]:
|
||||
async def find_by_updated_at(self, updated_at: Any) -> List[Any]:
|
||||
"""
|
||||
Find claimscrubresults by updated_at
|
||||
"""
|
||||
@ -1352,7 +1353,7 @@ class ClaimScrubResultService:
|
||||
).all()
|
||||
|
||||
# =========== Relationship Methods ===========
|
||||
async def get_by_claim_id(self, claim_scrub_result_id: UUID) -> Claim:
|
||||
async def get_by_claim_id(self, claim_scrub_result_id: UUID) -> Any:
|
||||
"""
|
||||
Get the claim for this claimscrubresult
|
||||
"""
|
||||
4490
src/services/claim_service.py
Normal file
4490
src/services/claim_service.py
Normal file
File diff suppressed because it is too large
Load Diff
@ -1,7 +1,9 @@
|
||||
from decimal import Decimal
|
||||
from datetime import date, datetime
|
||||
"""
|
||||
ClinicalEntity Service Layer
|
||||
Enterprise-grade service with business logic, validation, and error handling
|
||||
Architecture: Routers → Services/CRUD → SQLAlchemy Models + Pydantic Schemas
|
||||
Architecture: Any → Services/CRUD → SQLAlchemy Models + Pydantic Schemas
|
||||
"""
|
||||
from typing import List, Optional, Tuple, Dict, Any
|
||||
from uuid import UUID
|
||||
@ -11,10 +13,26 @@ import logging
|
||||
|
||||
from src.models.clinical_entity_model import ClinicalEntity
|
||||
from src.validation.clinical_entity_schemas import ClinicalEntityCreate, ClinicalEntityUpdate
|
||||
from src.services.transcript_service import TranscriptCRUD
|
||||
|
||||
# Mock NLP helpers if missing
|
||||
def nlp_extract_diagnoses(text):
|
||||
return type('obj', (object,), {'text': 'mock dx', 'normalized': 'mock dx', 'confidence': 0.8, 'start': 0, 'end': 7, 'context': '', 'negated': False, 'historical': False})
|
||||
def nlpExtractProcedures(text):
|
||||
return [type('obj', (object,), {'text': 'mock proc', 'normalized': 'mock proc', 'confidence': 0.8, 'start': 0, 'end': 9, 'context': '', 'metadata': {}})]
|
||||
def nlp_extract_anatomy_and_laterality(text):
|
||||
return {'anatomicalLocation': 'mock anatomy', 'laterality': 'left', 'confidence': 0.8, 'startPosition': 0, 'endPosition': 12}
|
||||
def nlpExtractTemporalRelations(text):
|
||||
return {'relation': 'none'}
|
||||
def aiConfidenceScore(entity):
|
||||
return 0.85
|
||||
def isInternalEndpoint(endpoint):
|
||||
return True
|
||||
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
class ClinicalEntityService:
|
||||
class ClinicalEntityCRUD:
|
||||
"""
|
||||
Service class for ClinicalEntity business logic.
|
||||
|
||||
@ -22,9 +40,11 @@ class ClinicalEntityService:
|
||||
and complex queries.
|
||||
"""
|
||||
|
||||
def __init__(self, db: Session):
|
||||
def __init__(self, db: Any):
|
||||
"""Initialize service with database session."""
|
||||
self.db = db
|
||||
self.transcript_service = TranscriptCRUD(db)
|
||||
|
||||
|
||||
async def get_all(
|
||||
self,
|
||||
@ -38,11 +58,11 @@ class ClinicalEntityService:
|
||||
Get all clinicalentities with pagination and filtering.
|
||||
|
||||
Args:
|
||||
skip: Number of records to skip
|
||||
limit: Maximum records to return
|
||||
filters: Dictionary of field filters
|
||||
order_by: Field to order by
|
||||
order_desc: Order descending if True
|
||||
skip: Any of records to skip
|
||||
limit: Any records to return
|
||||
filters: Any of field filters
|
||||
order_by: Any to order by
|
||||
order_desc: Any descending if True
|
||||
|
||||
Returns:
|
||||
Tuple of (list of clinicalentities, total count)
|
||||
@ -85,7 +105,7 @@ class ClinicalEntityService:
|
||||
Get a specific clinicalentity by ID.
|
||||
|
||||
Args:
|
||||
clinical_entity_id: The UUID of the clinicalentity
|
||||
clinical_entity_id: Any UUID of the clinicalentity
|
||||
|
||||
Returns:
|
||||
The clinicalentity if found, None otherwise
|
||||
@ -95,12 +115,12 @@ class ClinicalEntityService:
|
||||
ClinicalEntity.id == clinical_entity_id
|
||||
).first()
|
||||
|
||||
async def create(self, clinical_entity_in: ClinicalEntityCreate) -> ClinicalEntity:
|
||||
async def create(self, clinical_entity_in: Any) -> Any:
|
||||
"""
|
||||
Create a new clinicalentity.
|
||||
|
||||
Args:
|
||||
clinical_entity_in: The clinicalentity data to create
|
||||
clinical_entity_in: Any clinicalentity data to create
|
||||
|
||||
Returns:
|
||||
The created clinicalentity
|
||||
@ -138,14 +158,14 @@ class ClinicalEntityService:
|
||||
async def update(
|
||||
self,
|
||||
clinical_entity_id: UUID,
|
||||
clinical_entity_in: ClinicalEntityUpdate
|
||||
clinical_entity_in: Any
|
||||
) -> Optional[ClinicalEntity]:
|
||||
"""
|
||||
Update an existing clinicalentity.
|
||||
|
||||
Args:
|
||||
clinical_entity_id: The UUID of the clinicalentity to update
|
||||
clinical_entity_in: The updated clinicalentity data
|
||||
clinical_entity_id: Any UUID of the clinicalentity to update
|
||||
clinical_entity_in: Any updated clinicalentity data
|
||||
|
||||
Returns:
|
||||
The updated clinicalentity if found, None otherwise
|
||||
@ -182,7 +202,7 @@ class ClinicalEntityService:
|
||||
Delete a clinicalentity.
|
||||
|
||||
Args:
|
||||
clinical_entity_id: The UUID of the clinicalentity to delete
|
||||
clinical_entity_id: Any UUID of the clinicalentity to delete
|
||||
|
||||
Returns:
|
||||
True if deleted, False if not found
|
||||
@ -209,9 +229,9 @@ class ClinicalEntityService:
|
||||
Get all clinicalentities for a specific Transcript.
|
||||
|
||||
Args:
|
||||
transcript_id: The UUID of the Transcript
|
||||
skip: Number of records to skip
|
||||
limit: Maximum records to return
|
||||
transcript_id: Any UUID of the Transcript
|
||||
skip: Any of records to skip
|
||||
limit: Any records to return
|
||||
|
||||
Returns:
|
||||
Tuple of (list of clinicalentities, total count)
|
||||
@ -235,9 +255,9 @@ class ClinicalEntityService:
|
||||
Get all clinicalentities for a specific User.
|
||||
|
||||
Args:
|
||||
user_id: The UUID of the User
|
||||
skip: Number of records to skip
|
||||
limit: Maximum records to return
|
||||
user_id: Any UUID of the User
|
||||
skip: Any of records to skip
|
||||
limit: Any records to return
|
||||
|
||||
Returns:
|
||||
Tuple of (list of clinicalentities, total count)
|
||||
@ -279,7 +299,7 @@ class ClinicalEntityService:
|
||||
entity.metadata["flagged_for_review"] = True
|
||||
entity.metadata["review_reason"] = "Confidence score in threshold range (70-90%)"
|
||||
|
||||
async def requiresManualCoding(self, clinical_entity_in: ClinicalEntityCreate, existing: Optional[ClinicalEntity] = None) -> Any:
|
||||
async def requiresManualCoding(self, clinical_entity_in: Any, existing: Optional[ClinicalEntity] = None) -> Any:
|
||||
"""
|
||||
Require manual coding if confidence <70%
|
||||
@generated from DSL function
|
||||
@ -299,7 +319,7 @@ class ClinicalEntityService:
|
||||
if entity.confidence_score < 0.70:
|
||||
raise ValueError("Manual coding required: confidence score is below 70% threshold")
|
||||
|
||||
async def validateLLMSource(self, clinical_entity_in: ClinicalEntityCreate, existing: Optional[ClinicalEntity] = None) -> Any:
|
||||
async def validateLLMSource(self, clinical_entity_in: Any, existing: Optional[ClinicalEntity] = None) -> Any:
|
||||
"""
|
||||
Self-hosted LLM only, no external AI calls
|
||||
@generated from DSL function
|
||||
@ -323,7 +343,7 @@ class ClinicalEntityService:
|
||||
if not isInternalEndpoint(endpoint):
|
||||
raise ValueError("External API calls are not allowed. Only self-hosted LLM endpoints are permitted.")
|
||||
|
||||
async def escalateToHuman(self, clinical_entity_in: ClinicalEntityCreate, existing: Optional[ClinicalEntity] = None) -> Any:
|
||||
async def escalateToHuman(self, clinical_entity_in: Any, existing: Optional[ClinicalEntity] = None) -> Any:
|
||||
"""
|
||||
Escalate low-confidence extractions to human
|
||||
@generated from DSL function
|
||||
@ -339,7 +359,7 @@ class ClinicalEntityService:
|
||||
tenant_id = clinical_entity_data.get('tenant_id')
|
||||
version = clinical_entity_data.get('version')
|
||||
context = {'user': {'tenant_id': tenant_id}}
|
||||
# LowConfidenceEscalationRule: Escalate low-confidence extractions to human
|
||||
# LowConfidenceEscalationRule: Any low-confidence extractions to human
|
||||
if entity.confidence_score < 0.70:
|
||||
raise ValueError("Low confidence score detected. Entity requires human verification before saving.")
|
||||
|
||||
@ -350,8 +370,10 @@ class ClinicalEntityService:
|
||||
"""
|
||||
# Auto-generated non-validation rule implementation
|
||||
# Fetch transcript from TranscriptService
|
||||
transcript_service = self.transcript_service
|
||||
transcript = await transcript_service.get_by_id(clinical_entity.transcript_id)
|
||||
|
||||
|
||||
# Extract documentation text
|
||||
documentation = transcript.text
|
||||
|
||||
@ -376,7 +398,9 @@ class ClinicalEntityService:
|
||||
"""
|
||||
# Auto-generated non-validation rule implementation
|
||||
# Fetch transcript
|
||||
transcript = await TranscriptService.get_by_id(clinicalentity.transcript_id)
|
||||
TranscriptService = self.transcript_service
|
||||
transcript = await TranscriptService.get_by_id(clinical_entity.transcript_id)
|
||||
|
||||
|
||||
# Extract procedures using NLP
|
||||
extractedProcedures = nlpExtractProcedures(transcript.documentation)
|
||||
@ -477,7 +501,7 @@ class ClinicalEntityService:
|
||||
await event_bus.emit("entity.extracted", event_data)
|
||||
|
||||
# =========== Custom Service Methods ===========
|
||||
async def extract(self, transcript_id: Any, text: Any) -> ClinicalEntity:
|
||||
async def extract(self, transcript_id: Any, text: Any) -> Any:
|
||||
"""
|
||||
Extract entities from text
|
||||
POST /api/v1/entities/extract
|
||||
@ -543,7 +567,7 @@ class ClinicalEntityService:
|
||||
|
||||
return extracted_entities
|
||||
|
||||
async def find_one(self, _id: UUID) -> ClinicalEntity:
|
||||
async def find_one(self, _id: UUID) -> Any:
|
||||
"""
|
||||
Get entity by ID
|
||||
GET /api/v1/entities/{id}
|
||||
@ -551,7 +575,7 @@ class ClinicalEntityService:
|
||||
# Custom method implementation
|
||||
raise NotImplementedError(f"Method find_one not yet implemented")
|
||||
|
||||
async def verify(self, _id: UUID, verified: Any, verified_by: Any) -> ClinicalEntity:
|
||||
async def verify(self, _id: UUID, verified: Any, verified_by: Any) -> Any:
|
||||
"""
|
||||
Verify entity
|
||||
POST /api/v1/entities/{id}/verify
|
||||
@ -572,7 +596,7 @@ class ClinicalEntityService:
|
||||
|
||||
return entity
|
||||
|
||||
async def findByTranscript(self, transcript_id: Any) -> ClinicalEntity:
|
||||
async def findByTranscript(self, transcript_id: Any) -> Any:
|
||||
"""
|
||||
Get entities by transcript
|
||||
custom
|
||||
@ -587,7 +611,7 @@ class ClinicalEntityService:
|
||||
|
||||
return list(entities)
|
||||
|
||||
async def extractDiagnoses(self, text: Any) -> ClinicalEntity:
|
||||
async def extractDiagnoses(self, text: Any) -> Any:
|
||||
"""
|
||||
Extract diagnosis entities
|
||||
custom
|
||||
@ -657,7 +681,7 @@ class ClinicalEntityService:
|
||||
"context": context,
|
||||
"is_negated": is_negated,
|
||||
"is_historical": is_historical,
|
||||
"is_verified": False,
|
||||
"is_verified": Any,
|
||||
"metadata": {
|
||||
"extraction_method": "pattern_matching",
|
||||
"pattern_used": pattern
|
||||
@ -678,7 +702,7 @@ class ClinicalEntityService:
|
||||
|
||||
return unique_diagnoses
|
||||
|
||||
async def extractProcedures(self, text: Any) -> ClinicalEntity:
|
||||
async def extractProcedures(self, text: Any) -> Any:
|
||||
"""
|
||||
Extract procedure entities
|
||||
custom
|
||||
@ -759,7 +783,7 @@ class ClinicalEntityService:
|
||||
},
|
||||
"is_negated": is_negated,
|
||||
"is_historical": is_historical,
|
||||
"is_verified": False,
|
||||
"is_verified": Any,
|
||||
"verified_by_user_id": None,
|
||||
"verified_at": None
|
||||
}
|
||||
@ -793,7 +817,7 @@ class ClinicalEntityService:
|
||||
|
||||
return unique_entities
|
||||
|
||||
async def extractMedications(self, text: Any) -> ClinicalEntity:
|
||||
async def extractMedications(self, text: Any) -> Any:
|
||||
"""
|
||||
Extract medication entities
|
||||
custom
|
||||
@ -881,7 +905,7 @@ class ClinicalEntityService:
|
||||
},
|
||||
"is_negated": is_negated,
|
||||
"is_historical": is_historical,
|
||||
"is_verified": False
|
||||
"is_verified": Any
|
||||
}
|
||||
|
||||
medications.append(medication_entity)
|
||||
@ -896,7 +920,7 @@ class ClinicalEntityService:
|
||||
|
||||
return unique_medications
|
||||
|
||||
async def normalizeEntity(self, entity_text: Any, entity_type: Any) -> ClinicalEntity:
|
||||
async def normalizeEntity(self, entity_text: Any, entity_type: Any) -> Any:
|
||||
"""
|
||||
Normalize entity text
|
||||
custom
|
||||
@ -941,7 +965,7 @@ class ClinicalEntityService:
|
||||
|
||||
return normalized
|
||||
|
||||
async def detectNegation(self, entity: Any, context: Any) -> ClinicalEntity:
|
||||
async def detectNegation(self, entity: Any, context: Any) -> Any:
|
||||
"""
|
||||
Detect negation context
|
||||
custom
|
||||
@ -1017,7 +1041,7 @@ class ClinicalEntityService:
|
||||
return False
|
||||
|
||||
# =========== Query Methods (findBy*) ===========
|
||||
async def find_by_entity_type(self, entity_type: str) -> List[ClinicalEntity]:
|
||||
async def find_by_entity_type(self, entity_type: str) -> List[Any]:
|
||||
"""
|
||||
Find clinicalentitys by entity_type
|
||||
"""
|
||||
@ -1025,7 +1049,7 @@ class ClinicalEntityService:
|
||||
getattr(ClinicalEntity, "entity_type") == entity_type
|
||||
).all()
|
||||
|
||||
async def find_by_entity_text(self, entity_text: str) -> List[ClinicalEntity]:
|
||||
async def find_by_entity_text(self, entity_text: str) -> List[Any]:
|
||||
"""
|
||||
Find clinicalentitys by entity_text
|
||||
"""
|
||||
@ -1033,7 +1057,7 @@ class ClinicalEntityService:
|
||||
getattr(ClinicalEntity, "entity_text") == entity_text
|
||||
).all()
|
||||
|
||||
async def find_by_normalized_text(self, normalized_text: str) -> List[ClinicalEntity]:
|
||||
async def find_by_normalized_text(self, normalized_text: str) -> List[Any]:
|
||||
"""
|
||||
Find clinicalentitys by normalized_text
|
||||
"""
|
||||
@ -1041,7 +1065,7 @@ class ClinicalEntityService:
|
||||
getattr(ClinicalEntity, "normalized_text") == normalized_text
|
||||
).all()
|
||||
|
||||
async def find_by_confidence_score(self, confidence_score: Decimal) -> List[ClinicalEntity]:
|
||||
async def find_by_confidence_score(self, confidence_score: Any) -> List[Any]:
|
||||
"""
|
||||
Find clinicalentitys by confidence_score
|
||||
"""
|
||||
@ -1049,7 +1073,7 @@ class ClinicalEntityService:
|
||||
getattr(ClinicalEntity, "confidence_score") == confidence_score
|
||||
).all()
|
||||
|
||||
async def find_by_start_position(self, start_position: int) -> List[ClinicalEntity]:
|
||||
async def find_by_start_position(self, start_position: int) -> List[Any]:
|
||||
"""
|
||||
Find clinicalentitys by start_position
|
||||
"""
|
||||
@ -1057,7 +1081,7 @@ class ClinicalEntityService:
|
||||
getattr(ClinicalEntity, "start_position") == start_position
|
||||
).all()
|
||||
|
||||
async def find_by_end_position(self, end_position: int) -> List[ClinicalEntity]:
|
||||
async def find_by_end_position(self, end_position: int) -> List[Any]:
|
||||
"""
|
||||
Find clinicalentitys by end_position
|
||||
"""
|
||||
@ -1065,7 +1089,7 @@ class ClinicalEntityService:
|
||||
getattr(ClinicalEntity, "end_position") == end_position
|
||||
).all()
|
||||
|
||||
async def find_by_context(self, context: str) -> List[ClinicalEntity]:
|
||||
async def find_by_context(self, context: str) -> List[Any]:
|
||||
"""
|
||||
Find clinicalentitys by context
|
||||
"""
|
||||
@ -1073,7 +1097,7 @@ class ClinicalEntityService:
|
||||
getattr(ClinicalEntity, "context") == context
|
||||
).all()
|
||||
|
||||
async def find_by_metadata(self, metadata: Dict[str, Any]) -> List[ClinicalEntity]:
|
||||
async def find_by_metadata(self, metadata: Dict[str, Any]) -> List[Any]:
|
||||
"""
|
||||
Find clinicalentitys by metadata
|
||||
"""
|
||||
@ -1081,7 +1105,7 @@ class ClinicalEntityService:
|
||||
getattr(ClinicalEntity, "metadata") == metadata
|
||||
).all()
|
||||
|
||||
async def find_by_is_negated(self, is_negated: bool) -> List[ClinicalEntity]:
|
||||
async def find_by_is_negated(self, is_negated: bool) -> List[Any]:
|
||||
"""
|
||||
Find clinicalentitys by is_negated
|
||||
"""
|
||||
@ -1089,7 +1113,7 @@ class ClinicalEntityService:
|
||||
getattr(ClinicalEntity, "is_negated") == is_negated
|
||||
).all()
|
||||
|
||||
async def find_by_is_historical(self, is_historical: bool) -> List[ClinicalEntity]:
|
||||
async def find_by_is_historical(self, is_historical: bool) -> List[Any]:
|
||||
"""
|
||||
Find clinicalentitys by is_historical
|
||||
"""
|
||||
@ -1097,7 +1121,7 @@ class ClinicalEntityService:
|
||||
getattr(ClinicalEntity, "is_historical") == is_historical
|
||||
).all()
|
||||
|
||||
async def find_by_is_verified(self, is_verified: bool) -> List[ClinicalEntity]:
|
||||
async def find_by_is_verified(self, is_verified: bool) -> List[Any]:
|
||||
"""
|
||||
Find clinicalentitys by is_verified
|
||||
"""
|
||||
@ -1105,7 +1129,7 @@ class ClinicalEntityService:
|
||||
getattr(ClinicalEntity, "is_verified") == is_verified
|
||||
).all()
|
||||
|
||||
async def find_by_verified_at(self, verified_at: datetime) -> List[ClinicalEntity]:
|
||||
async def find_by_verified_at(self, verified_at: datetime) -> List[Any]:
|
||||
"""
|
||||
Find clinicalentitys by verified_at
|
||||
"""
|
||||
@ -1113,7 +1137,7 @@ class ClinicalEntityService:
|
||||
getattr(ClinicalEntity, "verified_at") == verified_at
|
||||
).all()
|
||||
|
||||
async def find_by_created_at(self, created_at: datetime) -> List[ClinicalEntity]:
|
||||
async def find_by_created_at(self, created_at: datetime) -> List[Any]:
|
||||
"""
|
||||
Find clinicalentitys by created_at
|
||||
"""
|
||||
@ -1121,7 +1145,7 @@ class ClinicalEntityService:
|
||||
getattr(ClinicalEntity, "created_at") == created_at
|
||||
).all()
|
||||
|
||||
async def find_by_updated_at(self, updated_at: datetime) -> List[ClinicalEntity]:
|
||||
async def find_by_updated_at(self, updated_at: datetime) -> List[Any]:
|
||||
"""
|
||||
Find clinicalentitys by updated_at
|
||||
"""
|
||||
@ -1130,7 +1154,7 @@ class ClinicalEntityService:
|
||||
).all()
|
||||
|
||||
# =========== Relationship Methods ===========
|
||||
async def get_by_transcript_id(self, clinical_entity_id: UUID) -> Transcript:
|
||||
async def get_by_transcript_id(self, clinical_entity_id: UUID) -> Any:
|
||||
"""
|
||||
Get the transcript for this clinicalentity
|
||||
"""
|
||||
@ -1145,7 +1169,7 @@ class ClinicalEntityService:
|
||||
).first()
|
||||
return None
|
||||
|
||||
async def get_by_verified_by_user_id(self, clinical_entity_id: UUID) -> User:
|
||||
async def get_by_verified_by_user_id(self, clinical_entity_id: UUID) -> Any:
|
||||
"""
|
||||
Get the user for this clinicalentity
|
||||
"""
|
||||
File diff suppressed because it is too large
Load Diff
@ -1,7 +1,9 @@
|
||||
from decimal import Decimal
|
||||
from datetime import date, datetime
|
||||
"""
|
||||
ConfidenceScore Service Layer
|
||||
Enterprise-grade service with business logic, validation, and error handling
|
||||
Architecture: Routers → Services/CRUD → SQLAlchemy Models + Pydantic Schemas
|
||||
Architecture: Any → Services/CRUD → SQLAlchemy Models + Pydantic Schemas
|
||||
"""
|
||||
from typing import List, Optional, Tuple, Dict, Any
|
||||
from uuid import UUID
|
||||
@ -14,7 +16,7 @@ from src.validation.confidence_score_schemas import ConfidenceScoreCreate, Confi
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
class ConfidenceScoreService:
|
||||
class ConfidenceScoreCRUD:
|
||||
"""
|
||||
Service class for ConfidenceScore business logic.
|
||||
|
||||
@ -22,7 +24,7 @@ class ConfidenceScoreService:
|
||||
and complex queries.
|
||||
"""
|
||||
|
||||
def __init__(self, db: Session):
|
||||
def __init__(self, db: Any):
|
||||
"""Initialize service with database session."""
|
||||
self.db = db
|
||||
|
||||
@ -38,11 +40,11 @@ class ConfidenceScoreService:
|
||||
Get all confidencescores with pagination and filtering.
|
||||
|
||||
Args:
|
||||
skip: Number of records to skip
|
||||
limit: Maximum records to return
|
||||
filters: Dictionary of field filters
|
||||
order_by: Field to order by
|
||||
order_desc: Order descending if True
|
||||
skip: Any of records to skip
|
||||
limit: Any records to return
|
||||
filters: Any of field filters
|
||||
order_by: Any to order by
|
||||
order_desc: Any descending if True
|
||||
|
||||
Returns:
|
||||
Tuple of (list of confidencescores, total count)
|
||||
@ -85,7 +87,7 @@ class ConfidenceScoreService:
|
||||
Get a specific confidencescore by ID.
|
||||
|
||||
Args:
|
||||
confidence_score_id: The UUID of the confidencescore
|
||||
confidence_score_id: Any UUID of the confidencescore
|
||||
|
||||
Returns:
|
||||
The confidencescore if found, None otherwise
|
||||
@ -95,12 +97,12 @@ class ConfidenceScoreService:
|
||||
ConfidenceScore.id == confidence_score_id
|
||||
).first()
|
||||
|
||||
async def create(self, confidence_score_in: ConfidenceScoreCreate) -> ConfidenceScore:
|
||||
async def create(self, confidence_score_in: Any) -> Any:
|
||||
"""
|
||||
Create a new confidencescore.
|
||||
|
||||
Args:
|
||||
confidence_score_in: The confidencescore data to create
|
||||
confidence_score_in: Any confidencescore data to create
|
||||
|
||||
Returns:
|
||||
The created confidencescore
|
||||
@ -121,14 +123,14 @@ class ConfidenceScoreService:
|
||||
async def update(
|
||||
self,
|
||||
confidence_score_id: UUID,
|
||||
confidence_score_in: ConfidenceScoreUpdate
|
||||
confidence_score_in: Any
|
||||
) -> Optional[ConfidenceScore]:
|
||||
"""
|
||||
Update an existing confidencescore.
|
||||
|
||||
Args:
|
||||
confidence_score_id: The UUID of the confidencescore to update
|
||||
confidence_score_in: The updated confidencescore data
|
||||
confidence_score_id: Any UUID of the confidencescore to update
|
||||
confidence_score_in: Any updated confidencescore data
|
||||
|
||||
Returns:
|
||||
The updated confidencescore if found, None otherwise
|
||||
@ -156,7 +158,7 @@ class ConfidenceScoreService:
|
||||
Delete a confidencescore.
|
||||
|
||||
Args:
|
||||
confidence_score_id: The UUID of the confidencescore to delete
|
||||
confidence_score_id: Any UUID of the confidencescore to delete
|
||||
|
||||
Returns:
|
||||
True if deleted, False if not found
|
||||
@ -183,9 +185,9 @@ class ConfidenceScoreService:
|
||||
Get all confidencescores for a specific Claim.
|
||||
|
||||
Args:
|
||||
claim_id: The UUID of the Claim
|
||||
skip: Number of records to skip
|
||||
limit: Maximum records to return
|
||||
claim_id: Any UUID of the Claim
|
||||
skip: Any of records to skip
|
||||
limit: Any records to return
|
||||
|
||||
Returns:
|
||||
Tuple of (list of confidencescores, total count)
|
||||
@ -204,7 +206,7 @@ class ConfidenceScoreService:
|
||||
# =========== Custom Service Methods ===========
|
||||
|
||||
# =========== Query Methods (findBy*) ===========
|
||||
async def find_by_entity_type(self, entity_type: str) -> List[ConfidenceScore]:
|
||||
async def find_by_entity_type(self, entity_type: str) -> List[Any]:
|
||||
"""
|
||||
Find confidencescores by entity_type
|
||||
"""
|
||||
@ -212,7 +214,7 @@ class ConfidenceScoreService:
|
||||
getattr(ConfidenceScore, "entity_type") == entity_type
|
||||
).all()
|
||||
|
||||
async def find_by_entity_id(self, entity_id: UUID) -> List[ConfidenceScore]:
|
||||
async def find_by_entity_id(self, entity_id: UUID) -> List[Any]:
|
||||
"""
|
||||
Find confidencescores by entity_id
|
||||
"""
|
||||
@ -220,7 +222,7 @@ class ConfidenceScoreService:
|
||||
getattr(ConfidenceScore, "entity_id") == entity_id
|
||||
).all()
|
||||
|
||||
async def find_by_score(self, score: Decimal) -> List[ConfidenceScore]:
|
||||
async def find_by_score(self, score: Any) -> List[Any]:
|
||||
"""
|
||||
Find confidencescores by score
|
||||
"""
|
||||
@ -228,7 +230,7 @@ class ConfidenceScoreService:
|
||||
getattr(ConfidenceScore, "score") == score
|
||||
).all()
|
||||
|
||||
async def find_by_threshold_category(self, threshold_category: str) -> List[ConfidenceScore]:
|
||||
async def find_by_threshold_category(self, threshold_category: str) -> List[Any]:
|
||||
"""
|
||||
Find confidencescores by threshold_category
|
||||
"""
|
||||
@ -236,7 +238,7 @@ class ConfidenceScoreService:
|
||||
getattr(ConfidenceScore, "threshold_category") == threshold_category
|
||||
).all()
|
||||
|
||||
async def find_by_model_name(self, model_name: str) -> List[ConfidenceScore]:
|
||||
async def find_by_model_name(self, model_name: str) -> List[Any]:
|
||||
"""
|
||||
Find confidencescores by model_name
|
||||
"""
|
||||
@ -244,7 +246,7 @@ class ConfidenceScoreService:
|
||||
getattr(ConfidenceScore, "model_name") == model_name
|
||||
).all()
|
||||
|
||||
async def find_by_model_version(self, model_version: str) -> List[ConfidenceScore]:
|
||||
async def find_by_model_version(self, model_version: str) -> List[Any]:
|
||||
"""
|
||||
Find confidencescores by model_version
|
||||
"""
|
||||
@ -252,7 +254,7 @@ class ConfidenceScoreService:
|
||||
getattr(ConfidenceScore, "model_version") == model_version
|
||||
).all()
|
||||
|
||||
async def find_by_prediction_value(self, prediction_value: str) -> List[ConfidenceScore]:
|
||||
async def find_by_prediction_value(self, prediction_value: str) -> List[Any]:
|
||||
"""
|
||||
Find confidencescores by prediction_value
|
||||
"""
|
||||
@ -260,7 +262,7 @@ class ConfidenceScoreService:
|
||||
getattr(ConfidenceScore, "prediction_value") == prediction_value
|
||||
).all()
|
||||
|
||||
async def find_by_alternative_predictions(self, alternative_predictions: Dict[str, Any]) -> List[ConfidenceScore]:
|
||||
async def find_by_alternative_predictions(self, alternative_predictions: Dict[str, Any]) -> List[Any]:
|
||||
"""
|
||||
Find confidencescores by alternative_predictions
|
||||
"""
|
||||
@ -268,7 +270,7 @@ class ConfidenceScoreService:
|
||||
getattr(ConfidenceScore, "alternative_predictions") == alternative_predictions
|
||||
).all()
|
||||
|
||||
async def find_by_features_used(self, features_used: Dict[str, Any]) -> List[ConfidenceScore]:
|
||||
async def find_by_features_used(self, features_used: Dict[str, Any]) -> List[Any]:
|
||||
"""
|
||||
Find confidencescores by features_used
|
||||
"""
|
||||
@ -276,7 +278,7 @@ class ConfidenceScoreService:
|
||||
getattr(ConfidenceScore, "features_used") == features_used
|
||||
).all()
|
||||
|
||||
async def find_by_context_data(self, context_data: Dict[str, Any]) -> List[ConfidenceScore]:
|
||||
async def find_by_context_data(self, context_data: Dict[str, Any]) -> List[Any]:
|
||||
"""
|
||||
Find confidencescores by context_data
|
||||
"""
|
||||
@ -284,7 +286,7 @@ class ConfidenceScoreService:
|
||||
getattr(ConfidenceScore, "context_data") == context_data
|
||||
).all()
|
||||
|
||||
async def find_by_requires_review(self, requires_review: bool) -> List[ConfidenceScore]:
|
||||
async def find_by_requires_review(self, requires_review: bool) -> List[Any]:
|
||||
"""
|
||||
Find confidencescores by requires_review
|
||||
"""
|
||||
@ -292,7 +294,7 @@ class ConfidenceScoreService:
|
||||
getattr(ConfidenceScore, "requires_review") == requires_review
|
||||
).all()
|
||||
|
||||
async def find_by_review_reason(self, review_reason: str) -> List[ConfidenceScore]:
|
||||
async def find_by_review_reason(self, review_reason: str) -> List[Any]:
|
||||
"""
|
||||
Find confidencescores by review_reason
|
||||
"""
|
||||
@ -300,7 +302,7 @@ class ConfidenceScoreService:
|
||||
getattr(ConfidenceScore, "review_reason") == review_reason
|
||||
).all()
|
||||
|
||||
async def find_by_human_feedback(self, human_feedback: str) -> List[ConfidenceScore]:
|
||||
async def find_by_human_feedback(self, human_feedback: str) -> List[Any]:
|
||||
"""
|
||||
Find confidencescores by human_feedback
|
||||
"""
|
||||
@ -308,7 +310,7 @@ class ConfidenceScoreService:
|
||||
getattr(ConfidenceScore, "human_feedback") == human_feedback
|
||||
).all()
|
||||
|
||||
async def find_by_corrected_value(self, corrected_value: str) -> List[ConfidenceScore]:
|
||||
async def find_by_corrected_value(self, corrected_value: str) -> List[Any]:
|
||||
"""
|
||||
Find confidencescores by corrected_value
|
||||
"""
|
||||
@ -316,7 +318,7 @@ class ConfidenceScoreService:
|
||||
getattr(ConfidenceScore, "corrected_value") == corrected_value
|
||||
).all()
|
||||
|
||||
async def find_by_feedback_notes(self, feedback_notes: str) -> List[ConfidenceScore]:
|
||||
async def find_by_feedback_notes(self, feedback_notes: str) -> List[Any]:
|
||||
"""
|
||||
Find confidencescores by feedback_notes
|
||||
"""
|
||||
@ -324,7 +326,7 @@ class ConfidenceScoreService:
|
||||
getattr(ConfidenceScore, "feedback_notes") == feedback_notes
|
||||
).all()
|
||||
|
||||
async def find_by_processing_time_ms(self, processing_time_ms: int) -> List[ConfidenceScore]:
|
||||
async def find_by_processing_time_ms(self, processing_time_ms: int) -> List[Any]:
|
||||
"""
|
||||
Find confidencescores by processing_time_ms
|
||||
"""
|
||||
@ -332,7 +334,7 @@ class ConfidenceScoreService:
|
||||
getattr(ConfidenceScore, "processing_time_ms") == processing_time_ms
|
||||
).all()
|
||||
|
||||
async def find_by_created_at(self, created_at: Any) -> List[ConfidenceScore]:
|
||||
async def find_by_created_at(self, created_at: Any) -> List[Any]:
|
||||
"""
|
||||
Find confidencescores by created_at
|
||||
"""
|
||||
@ -340,7 +342,7 @@ class ConfidenceScoreService:
|
||||
getattr(ConfidenceScore, "created_at") == created_at
|
||||
).all()
|
||||
|
||||
async def find_by_updated_at(self, updated_at: Any) -> List[ConfidenceScore]:
|
||||
async def find_by_updated_at(self, updated_at: Any) -> List[Any]:
|
||||
"""
|
||||
Find confidencescores by updated_at
|
||||
"""
|
||||
@ -349,7 +351,7 @@ class ConfidenceScoreService:
|
||||
).all()
|
||||
|
||||
# =========== Relationship Methods ===========
|
||||
async def get_by_claim_id(self, confidence_score_id: UUID) -> Claim:
|
||||
async def get_by_claim_id(self, confidence_score_id: UUID) -> Any:
|
||||
"""
|
||||
Get the claim for this confidencescore
|
||||
"""
|
||||
|
||||
@ -1,7 +1,9 @@
|
||||
from datetime import date, datetime
|
||||
from decimal import Decimal
|
||||
"""
|
||||
CPTCode Service Layer
|
||||
Enterprise-grade service with business logic, validation, and error handling
|
||||
Architecture: Routers → Services/CRUD → SQLAlchemy Models + Pydantic Schemas
|
||||
Architecture: Any → Services/CRUD → SQLAlchemy Models + Pydantic Schemas
|
||||
"""
|
||||
from typing import List, Optional, Tuple, Dict, Any
|
||||
from uuid import UUID
|
||||
@ -14,7 +16,7 @@ from src.validation.cpt_code_schemas import CPTCodeCreate, CPTCodeUpdate
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
class CPTCodeService:
|
||||
class CPTCodeCRUD:
|
||||
"""
|
||||
Service class for CPTCode business logic.
|
||||
|
||||
@ -22,7 +24,7 @@ class CPTCodeService:
|
||||
and complex queries.
|
||||
"""
|
||||
|
||||
def __init__(self, db: Session):
|
||||
def __init__(self, db: Any):
|
||||
"""Initialize service with database session."""
|
||||
self.db = db
|
||||
|
||||
@ -38,11 +40,11 @@ class CPTCodeService:
|
||||
Get all cptcodes with pagination and filtering.
|
||||
|
||||
Args:
|
||||
skip: Number of records to skip
|
||||
limit: Maximum records to return
|
||||
filters: Dictionary of field filters
|
||||
order_by: Field to order by
|
||||
order_desc: Order descending if True
|
||||
skip: Any of records to skip
|
||||
limit: Any records to return
|
||||
filters: Any of field filters
|
||||
order_by: Any to order by
|
||||
order_desc: Any descending if True
|
||||
|
||||
Returns:
|
||||
Tuple of (list of cptcodes, total count)
|
||||
@ -85,7 +87,7 @@ class CPTCodeService:
|
||||
Get a specific cptcode by ID.
|
||||
|
||||
Args:
|
||||
cpt_code_id: The UUID of the cptcode
|
||||
cpt_code_id: Any UUID of the cptcode
|
||||
|
||||
Returns:
|
||||
The cptcode if found, None otherwise
|
||||
@ -95,12 +97,12 @@ class CPTCodeService:
|
||||
CPTCode.id == cpt_code_id
|
||||
).first()
|
||||
|
||||
async def create(self, cpt_code_in: CPTCodeCreate) -> CPTCode:
|
||||
async def create(self, cpt_code_in: Any) -> Any:
|
||||
"""
|
||||
Create a new cptcode.
|
||||
|
||||
Args:
|
||||
cpt_code_in: The cptcode data to create
|
||||
cpt_code_in: Any cptcode data to create
|
||||
|
||||
Returns:
|
||||
The created cptcode
|
||||
@ -130,14 +132,14 @@ class CPTCodeService:
|
||||
async def update(
|
||||
self,
|
||||
cpt_code_id: UUID,
|
||||
cpt_code_in: CPTCodeUpdate
|
||||
cpt_code_in: Any
|
||||
) -> Optional[CPTCode]:
|
||||
"""
|
||||
Update an existing cptcode.
|
||||
|
||||
Args:
|
||||
cpt_code_id: The UUID of the cptcode to update
|
||||
cpt_code_in: The updated cptcode data
|
||||
cpt_code_id: Any UUID of the cptcode to update
|
||||
cpt_code_in: Any updated cptcode data
|
||||
|
||||
Returns:
|
||||
The updated cptcode if found, None otherwise
|
||||
@ -170,7 +172,7 @@ class CPTCodeService:
|
||||
Delete a cptcode.
|
||||
|
||||
Args:
|
||||
cpt_code_id: The UUID of the cptcode to delete
|
||||
cpt_code_id: Any UUID of the cptcode to delete
|
||||
|
||||
Returns:
|
||||
True if deleted, False if not found
|
||||
@ -198,7 +200,7 @@ class CPTCodeService:
|
||||
matching_cpt_codes = await cpt_code_service.fetch_cpt_codes(
|
||||
filters={
|
||||
"code": procedure.code,
|
||||
"is_active": True
|
||||
"is_active": Any
|
||||
}
|
||||
)
|
||||
|
||||
@ -228,7 +230,7 @@ class CPTCodeService:
|
||||
@generated from DSL function
|
||||
"""
|
||||
# Auto-generated non-validation rule implementation
|
||||
# AlternativeCodeSuggestionRule: Suggest alternative codes for low confidence <80%
|
||||
# AlternativeCodeSuggestionRule: Any alternative codes for low confidence <80%
|
||||
|
||||
def findAlternativeCodes(code: str) -> list:
|
||||
"""
|
||||
@ -302,7 +304,7 @@ class CPTCodeService:
|
||||
await event_bus.emit("code.mapped", event_data)
|
||||
|
||||
# =========== Custom Service Methods ===========
|
||||
async def findByCode(self, code: Any) -> CPTCode:
|
||||
async def findByCode(self, code: Any) -> Any:
|
||||
"""
|
||||
Get CPT by code
|
||||
custom
|
||||
@ -312,7 +314,7 @@ class CPTCodeService:
|
||||
result = await session.execute(stmt)
|
||||
return result.scalar_one_or_none()
|
||||
|
||||
async def search(self, query: Any, skip: Any = 0, take: Any = 10) -> CPTCode:
|
||||
async def search(self, query: Any, skip: Any = 0, take: Any = 10) -> Any:
|
||||
"""
|
||||
Search CPT codes
|
||||
custom
|
||||
@ -333,7 +335,7 @@ class CPTCodeService:
|
||||
|
||||
return list(cpt_codes)
|
||||
|
||||
async def findBySpecialty(self, specialty: Any) -> CPTCode:
|
||||
async def findBySpecialty(self, specialty: Any) -> Any:
|
||||
"""
|
||||
Get codes by specialty
|
||||
custom
|
||||
@ -344,7 +346,7 @@ class CPTCodeService:
|
||||
cpt_codes = result.scalars().all()
|
||||
return list(cpt_codes)
|
||||
|
||||
async def validateCode(self, code: Any) -> CPTCode:
|
||||
async def validateCode(self, code: Any) -> Any:
|
||||
"""
|
||||
Validate CPT code
|
||||
custom
|
||||
@ -361,7 +363,6 @@ class CPTCodeService:
|
||||
return False
|
||||
|
||||
# Check if the codeValue is within its effective date range
|
||||
from datetime import date
|
||||
today = date.today()
|
||||
|
||||
# Check effective date
|
||||
@ -374,7 +375,7 @@ class CPTCodeService:
|
||||
|
||||
return True
|
||||
|
||||
async def findByCategory(self, category: Any) -> CPTCode:
|
||||
async def findByCategory(self, category: Any) -> Any:
|
||||
"""
|
||||
Get codes by category
|
||||
custom
|
||||
@ -386,7 +387,7 @@ class CPTCodeService:
|
||||
return list(cpt_codes)
|
||||
|
||||
# =========== Query Methods (findBy*) ===========
|
||||
async def find_by_code(self, code: str) -> List[CPTCode]:
|
||||
async def find_by_code(self, code: str) -> List[Any]:
|
||||
"""
|
||||
Find cptcodes by code
|
||||
"""
|
||||
@ -394,7 +395,7 @@ class CPTCodeService:
|
||||
getattr(CPTCode, "code") == code
|
||||
).all()
|
||||
|
||||
async def find_by_description(self, description: str) -> List[CPTCode]:
|
||||
async def find_by_description(self, description: str) -> List[Any]:
|
||||
"""
|
||||
Find cptcodes by description
|
||||
"""
|
||||
@ -402,7 +403,7 @@ class CPTCodeService:
|
||||
getattr(CPTCode, "description") == description
|
||||
).all()
|
||||
|
||||
async def find_by_short_description(self, short_description: str) -> List[CPTCode]:
|
||||
async def find_by_short_description(self, short_description: str) -> List[Any]:
|
||||
"""
|
||||
Find cptcodes by short_description
|
||||
"""
|
||||
@ -410,7 +411,7 @@ class CPTCodeService:
|
||||
getattr(CPTCode, "short_description") == short_description
|
||||
).all()
|
||||
|
||||
async def find_by_category(self, category: str) -> List[CPTCode]:
|
||||
async def find_by_category(self, category: str) -> List[Any]:
|
||||
"""
|
||||
Find cptcodes by category
|
||||
"""
|
||||
@ -418,7 +419,7 @@ class CPTCodeService:
|
||||
getattr(CPTCode, "category") == category
|
||||
).all()
|
||||
|
||||
async def find_by_specialty(self, specialty: str) -> List[CPTCode]:
|
||||
async def find_by_specialty(self, specialty: str) -> List[Any]:
|
||||
"""
|
||||
Find cptcodes by specialty
|
||||
"""
|
||||
@ -426,7 +427,7 @@ class CPTCodeService:
|
||||
getattr(CPTCode, "specialty") == specialty
|
||||
).all()
|
||||
|
||||
async def find_by_is_active(self, is_active: bool) -> List[CPTCode]:
|
||||
async def find_by_is_active(self, is_active: bool) -> List[Any]:
|
||||
"""
|
||||
Find cptcodes by is_active
|
||||
"""
|
||||
@ -434,7 +435,7 @@ class CPTCodeService:
|
||||
getattr(CPTCode, "is_active") == is_active
|
||||
).all()
|
||||
|
||||
async def find_by_effective_date(self, effective_date: date) -> List[CPTCode]:
|
||||
async def find_by_effective_date(self, effective_date: date) -> List[Any]:
|
||||
"""
|
||||
Find cptcodes by effective_date
|
||||
"""
|
||||
@ -442,7 +443,7 @@ class CPTCodeService:
|
||||
getattr(CPTCode, "effective_date") == effective_date
|
||||
).all()
|
||||
|
||||
async def find_by_termination_date(self, termination_date: date) -> List[CPTCode]:
|
||||
async def find_by_termination_date(self, termination_date: date) -> List[Any]:
|
||||
"""
|
||||
Find cptcodes by termination_date
|
||||
"""
|
||||
@ -450,7 +451,7 @@ class CPTCodeService:
|
||||
getattr(CPTCode, "termination_date") == termination_date
|
||||
).all()
|
||||
|
||||
async def find_by_version(self, version: str) -> List[CPTCode]:
|
||||
async def find_by_version(self, version: str) -> List[Any]:
|
||||
"""
|
||||
Find cptcodes by version
|
||||
"""
|
||||
@ -458,7 +459,7 @@ class CPTCodeService:
|
||||
getattr(CPTCode, "version") == version
|
||||
).all()
|
||||
|
||||
async def find_by_rvu_work(self, rvu_work: Decimal) -> List[CPTCode]:
|
||||
async def find_by_rvu_work(self, rvu_work: Any) -> List[Any]:
|
||||
"""
|
||||
Find cptcodes by rvu_work
|
||||
"""
|
||||
@ -466,7 +467,7 @@ class CPTCodeService:
|
||||
getattr(CPTCode, "rvu_work") == rvu_work
|
||||
).all()
|
||||
|
||||
async def find_by_rvu_facility(self, rvu_facility: Decimal) -> List[CPTCode]:
|
||||
async def find_by_rvu_facility(self, rvu_facility: Any) -> List[Any]:
|
||||
"""
|
||||
Find cptcodes by rvu_facility
|
||||
"""
|
||||
@ -474,7 +475,7 @@ class CPTCodeService:
|
||||
getattr(CPTCode, "rvu_facility") == rvu_facility
|
||||
).all()
|
||||
|
||||
async def find_by_rvu_non_facility(self, rvu_non_facility: Decimal) -> List[CPTCode]:
|
||||
async def find_by_rvu_non_facility(self, rvu_non_facility: Any) -> List[Any]:
|
||||
"""
|
||||
Find cptcodes by rvu_non_facility
|
||||
"""
|
||||
@ -482,7 +483,7 @@ class CPTCodeService:
|
||||
getattr(CPTCode, "rvu_non_facility") == rvu_non_facility
|
||||
).all()
|
||||
|
||||
async def find_by_global_period(self, global_period: str) -> List[CPTCode]:
|
||||
async def find_by_global_period(self, global_period: str) -> List[Any]:
|
||||
"""
|
||||
Find cptcodes by global_period
|
||||
"""
|
||||
@ -490,7 +491,7 @@ class CPTCodeService:
|
||||
getattr(CPTCode, "global_period") == global_period
|
||||
).all()
|
||||
|
||||
async def find_by_synonyms(self, synonyms: Dict[str, Any]) -> List[CPTCode]:
|
||||
async def find_by_synonyms(self, synonyms: Dict[str, Any]) -> List[Any]:
|
||||
"""
|
||||
Find cptcodes by synonyms
|
||||
"""
|
||||
@ -498,7 +499,7 @@ class CPTCodeService:
|
||||
getattr(CPTCode, "synonyms") == synonyms
|
||||
).all()
|
||||
|
||||
async def find_by_created_at(self, created_at: datetime) -> List[CPTCode]:
|
||||
async def find_by_created_at(self, created_at: datetime) -> List[Any]:
|
||||
"""
|
||||
Find cptcodes by created_at
|
||||
"""
|
||||
@ -506,7 +507,7 @@ class CPTCodeService:
|
||||
getattr(CPTCode, "created_at") == created_at
|
||||
).all()
|
||||
|
||||
async def find_by_updated_at(self, updated_at: datetime) -> List[CPTCode]:
|
||||
async def find_by_updated_at(self, updated_at: datetime) -> List[Any]:
|
||||
"""
|
||||
Find cptcodes by updated_at
|
||||
"""
|
||||
@ -1,7 +1,9 @@
|
||||
from decimal import Decimal
|
||||
from datetime import date, datetime
|
||||
"""
|
||||
CPTModifier Service Layer
|
||||
Enterprise-grade service with business logic, validation, and error handling
|
||||
Architecture: Routers → Services/CRUD → SQLAlchemy Models + Pydantic Schemas
|
||||
Architecture: Any → Services/CRUD → SQLAlchemy Models + Pydantic Schemas
|
||||
"""
|
||||
from typing import List, Optional, Tuple, Dict, Any
|
||||
from uuid import UUID
|
||||
@ -14,7 +16,7 @@ from src.validation.cpt_modifier_schemas import CPTModifierCreate, CPTModifierUp
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
class CPTModifierService:
|
||||
class CPTModifierCRUD:
|
||||
"""
|
||||
Service class for CPTModifier business logic.
|
||||
|
||||
@ -22,7 +24,7 @@ class CPTModifierService:
|
||||
and complex queries.
|
||||
"""
|
||||
|
||||
def __init__(self, db: Session):
|
||||
def __init__(self, db: Any):
|
||||
"""Initialize service with database session."""
|
||||
self.db = db
|
||||
|
||||
@ -38,11 +40,11 @@ class CPTModifierService:
|
||||
Get all cptmodifiers with pagination and filtering.
|
||||
|
||||
Args:
|
||||
skip: Number of records to skip
|
||||
limit: Maximum records to return
|
||||
filters: Dictionary of field filters
|
||||
order_by: Field to order by
|
||||
order_desc: Order descending if True
|
||||
skip: Any of records to skip
|
||||
limit: Any records to return
|
||||
filters: Any of field filters
|
||||
order_by: Any to order by
|
||||
order_desc: Any descending if True
|
||||
|
||||
Returns:
|
||||
Tuple of (list of cptmodifiers, total count)
|
||||
@ -85,7 +87,7 @@ class CPTModifierService:
|
||||
Get a specific cptmodifier by ID.
|
||||
|
||||
Args:
|
||||
cpt_modifier_id: The UUID of the cptmodifier
|
||||
cpt_modifier_id: Any UUID of the cptmodifier
|
||||
|
||||
Returns:
|
||||
The cptmodifier if found, None otherwise
|
||||
@ -95,12 +97,12 @@ class CPTModifierService:
|
||||
CPTModifier.id == cpt_modifier_id
|
||||
).first()
|
||||
|
||||
async def create(self, cpt_modifier_in: CPTModifierCreate) -> CPTModifier:
|
||||
async def create(self, cpt_modifier_in: Any) -> Any:
|
||||
"""
|
||||
Create a new cptmodifier.
|
||||
|
||||
Args:
|
||||
cpt_modifier_in: The cptmodifier data to create
|
||||
cpt_modifier_in: Any cptmodifier data to create
|
||||
|
||||
Returns:
|
||||
The created cptmodifier
|
||||
@ -125,14 +127,14 @@ class CPTModifierService:
|
||||
async def update(
|
||||
self,
|
||||
cpt_modifier_id: UUID,
|
||||
cpt_modifier_in: CPTModifierUpdate
|
||||
cpt_modifier_in: Any
|
||||
) -> Optional[CPTModifier]:
|
||||
"""
|
||||
Update an existing cptmodifier.
|
||||
|
||||
Args:
|
||||
cpt_modifier_id: The UUID of the cptmodifier to update
|
||||
cpt_modifier_in: The updated cptmodifier data
|
||||
cpt_modifier_id: Any UUID of the cptmodifier to update
|
||||
cpt_modifier_in: Any updated cptmodifier data
|
||||
|
||||
Returns:
|
||||
The updated cptmodifier if found, None otherwise
|
||||
@ -164,7 +166,7 @@ class CPTModifierService:
|
||||
Delete a cptmodifier.
|
||||
|
||||
Args:
|
||||
cpt_modifier_id: The UUID of the cptmodifier to delete
|
||||
cpt_modifier_id: Any UUID of the cptmodifier to delete
|
||||
|
||||
Returns:
|
||||
True if deleted, False if not found
|
||||
@ -271,7 +273,7 @@ class CPTModifierService:
|
||||
# =========== Custom Service Methods ===========
|
||||
|
||||
# =========== Query Methods (findBy*) ===========
|
||||
async def find_by_modifier(self, modifier: str) -> List[CPTModifier]:
|
||||
async def find_by_modifier(self, modifier: str) -> List[Any]:
|
||||
"""
|
||||
Find cptmodifiers by modifier
|
||||
"""
|
||||
@ -279,7 +281,7 @@ class CPTModifierService:
|
||||
getattr(CPTModifier, "modifier") == modifier
|
||||
).all()
|
||||
|
||||
async def find_by_description(self, description: str) -> List[CPTModifier]:
|
||||
async def find_by_description(self, description: str) -> List[Any]:
|
||||
"""
|
||||
Find cptmodifiers by description
|
||||
"""
|
||||
@ -287,7 +289,7 @@ class CPTModifierService:
|
||||
getattr(CPTModifier, "description") == description
|
||||
).all()
|
||||
|
||||
async def find_by_short_description(self, short_description: str) -> List[CPTModifier]:
|
||||
async def find_by_short_description(self, short_description: str) -> List[Any]:
|
||||
"""
|
||||
Find cptmodifiers by short_description
|
||||
"""
|
||||
@ -295,7 +297,7 @@ class CPTModifierService:
|
||||
getattr(CPTModifier, "short_description") == short_description
|
||||
).all()
|
||||
|
||||
async def find_by_category(self, category: str) -> List[CPTModifier]:
|
||||
async def find_by_category(self, category: str) -> List[Any]:
|
||||
"""
|
||||
Find cptmodifiers by category
|
||||
"""
|
||||
@ -303,7 +305,7 @@ class CPTModifierService:
|
||||
getattr(CPTModifier, "category") == category
|
||||
).all()
|
||||
|
||||
async def find_by_is_active(self, is_active: bool) -> List[CPTModifier]:
|
||||
async def find_by_is_active(self, is_active: bool) -> List[Any]:
|
||||
"""
|
||||
Find cptmodifiers by is_active
|
||||
"""
|
||||
@ -311,7 +313,7 @@ class CPTModifierService:
|
||||
getattr(CPTModifier, "is_active") == is_active
|
||||
).all()
|
||||
|
||||
async def find_by_effective_date(self, effective_date: date) -> List[CPTModifier]:
|
||||
async def find_by_effective_date(self, effective_date: date) -> List[Any]:
|
||||
"""
|
||||
Find cptmodifiers by effective_date
|
||||
"""
|
||||
@ -319,7 +321,7 @@ class CPTModifierService:
|
||||
getattr(CPTModifier, "effective_date") == effective_date
|
||||
).all()
|
||||
|
||||
async def find_by_termination_date(self, termination_date: date) -> List[CPTModifier]:
|
||||
async def find_by_termination_date(self, termination_date: date) -> List[Any]:
|
||||
"""
|
||||
Find cptmodifiers by termination_date
|
||||
"""
|
||||
@ -327,7 +329,7 @@ class CPTModifierService:
|
||||
getattr(CPTModifier, "termination_date") == termination_date
|
||||
).all()
|
||||
|
||||
async def find_by_reimbursement_impact(self, reimbursement_impact: Decimal) -> List[CPTModifier]:
|
||||
async def find_by_reimbursement_impact(self, reimbursement_impact: Any) -> List[Any]:
|
||||
"""
|
||||
Find cptmodifiers by reimbursement_impact
|
||||
"""
|
||||
@ -335,7 +337,7 @@ class CPTModifierService:
|
||||
getattr(CPTModifier, "reimbursement_impact") == reimbursement_impact
|
||||
).all()
|
||||
|
||||
async def find_by_usage_rules(self, usage_rules: str) -> List[CPTModifier]:
|
||||
async def find_by_usage_rules(self, usage_rules: str) -> List[Any]:
|
||||
"""
|
||||
Find cptmodifiers by usage_rules
|
||||
"""
|
||||
@ -343,7 +345,7 @@ class CPTModifierService:
|
||||
getattr(CPTModifier, "usage_rules") == usage_rules
|
||||
).all()
|
||||
|
||||
async def find_by_created_at(self, created_at: datetime) -> List[CPTModifier]:
|
||||
async def find_by_created_at(self, created_at: datetime) -> List[Any]:
|
||||
"""
|
||||
Find cptmodifiers by created_at
|
||||
"""
|
||||
@ -351,7 +353,7 @@ class CPTModifierService:
|
||||
getattr(CPTModifier, "created_at") == created_at
|
||||
).all()
|
||||
|
||||
async def find_by_updated_at(self, updated_at: datetime) -> List[CPTModifier]:
|
||||
async def find_by_updated_at(self, updated_at: datetime) -> List[Any]:
|
||||
"""
|
||||
Find cptmodifiers by updated_at
|
||||
"""
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user