Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
182 changes: 159 additions & 23 deletions app/core/documents/cruds_documents.py
Original file line number Diff line number Diff line change
@@ -1,21 +1,50 @@
from collections import defaultdict
from datetime import UTC, datetime
from uuid import UUID

from sqlalchemy import delete, select, update
from sqlalchemy import ScalarSelect, delete, func, select, update
from sqlalchemy.ext.asyncio import AsyncSession
from sqlalchemy.orm import selectinload
from sqlalchemy.orm import noload, selectinload

from app.core.documents import models_documents, schemas_documents
from app.core.documents.types_documenso import DocumentStatus
from app.core.documents.utils_documents import (
document_complete_model_to_schema,
document_model_to_schema,
document_with_team_info_model_to_schema,
document_with_user_model_to_schema,
team_complete_model_to_schema,
team_model_to_schema,
template_complete_model_to_schema,
template_model_to_schema,
template_complete_with_documents_model_to_schema,
template_with_statistics_model_to_schema,
)


def _template_statistics_subqueries() -> tuple[
ScalarSelect[int],
ScalarSelect[int],
ScalarSelect[int],
ScalarSelect[int],
]:
def base(*extra):
return (
select(func.count(models_documents.DocumentDocument.id))
.where(
models_documents.DocumentDocument.template_id
== models_documents.DocumentTemplate.id,
*extra,
)
.correlate(models_documents.DocumentTemplate)
.scalar_subquery()
)

return (
base(),
base(models_documents.DocumentDocument.status == DocumentStatus.COMPLETED),
base(models_documents.DocumentDocument.status == DocumentStatus.PENDING),
base(models_documents.DocumentDocument.status == DocumentStatus.REJECTED),
)


# region Team


Expand Down Expand Up @@ -50,25 +79,74 @@ async def get_teams_by_group_ids(
db: AsyncSession,
group_ids: list[str],
) -> list[schemas_documents.TeamComplete]:
"""Return a team by its internal id."""
"""Return teams by their group ids, along with their templates and statistics."""

result = (
teams = (
(
await db.execute(
select(models_documents.DocumentTeam)
.where(
models_documents.DocumentTeam.group_id.in_(group_ids),
)
.options(
selectinload(models_documents.DocumentTeam.templates),
selectinload(models_documents.DocumentTeam.group),
noload(models_documents.DocumentTeam.templates),
),
)
)
.scalars()
.all()
)
return [team_complete_model_to_schema(team) for team in result]

if not teams:
return []

team_ids = [team.id for team in teams]

total_sq, completed_sq, pending_sq, rejected_sq = _template_statistics_subqueries()

templates_result = await db.execute(
select(
models_documents.DocumentTemplate,
total_sq.label("total_documents"),
completed_sq.label("total_signed_documents"),
pending_sq.label("total_pending_documents"),
rejected_sq.label("total_rejected_documents"),
)
.where(
models_documents.DocumentTemplate.team_id.in_(team_ids),
)
.options(
noload(models_documents.DocumentTemplate.documents),
),
)

templates_by_team_id: dict[UUID, list[schemas_documents.TemplateWithStatistics]] = (
defaultdict(list)
)
for (
template,
total_documents,
total_signed_documents,
total_pending_documents,
total_rejected_documents,
) in templates_result.all():
templates_by_team_id[template.team_id].append(
template_with_statistics_model_to_schema(
template,
schemas_documents.TemplateStatistics(
total_documents=total_documents,
total_signed_documents=total_signed_documents,
total_pending_documents=total_pending_documents,
total_rejected_documents=total_rejected_documents,
),
),
)

return [
team_complete_model_to_schema(team, templates_by_team_id.get(team.id, []))
for team in teams
]


async def get_team_by_name(
Expand All @@ -91,6 +169,26 @@ async def get_team_by_name(
return team_model_to_schema(result) if result else None


async def get_team_by_team_id(
db: AsyncSession,
team_id: int,
) -> schemas_documents.Team | None:
"""Return a team by its Documenso team id."""

result = (
(
await db.execute(
select(models_documents.DocumentTeam).where(
models_documents.DocumentTeam.team_id == team_id,
),
)
)
.scalars()
.first()
)
return team_model_to_schema(result) if result else None


async def get_team_by_group_id(
db: AsyncSession,
group_id: str,
Expand Down Expand Up @@ -156,24 +254,53 @@ async def delete_team(db: AsyncSession, team_id: UUID) -> None:
# region Template


async def get_team_templates(
async def get_team_templates_with_statistics(
db: AsyncSession,
team_id: UUID,
) -> list[schemas_documents.Template]:
"""Return all templates filtered by team."""
) -> list[schemas_documents.TemplateWithStatistics]:
"""Return all templates filtered by team, with document statistics."""

total_sq, completed_sq, pending_sq, rejected_sq = _template_statistics_subqueries()

result = await db.execute(
select(models_documents.DocumentTemplate).where(
select(
models_documents.DocumentTemplate,
total_sq.label("total_documents"),
completed_sq.label("total_signed_documents"),
pending_sq.label("total_pending_documents"),
rejected_sq.label("total_rejected_documents"),
)
.where(
models_documents.DocumentTemplate.team_id == team_id,
)
.options(
noload(models_documents.DocumentTemplate.documents),
),
)
return [template_model_to_schema(template) for template in result.scalars().all()]
return [
template_with_statistics_model_to_schema(
template,
schemas_documents.TemplateStatistics(
total_documents=total_documents,
total_signed_documents=total_signed_documents,
total_pending_documents=total_pending_documents,
total_rejected_documents=total_rejected_documents,
),
)
for (
template,
total_documents,
total_signed_documents,
total_pending_documents,
total_rejected_documents,
) in result.all()
]


async def get_template_by_id(
db: AsyncSession,
template_id: UUID,
) -> schemas_documents.TemplateComplete | None:
) -> schemas_documents.TemplateCompleteWithDocuments | None:
"""Return a template by its internal id."""

result = (
Expand All @@ -191,13 +318,13 @@ async def get_template_by_id(
.scalars()
.first()
)
return template_complete_model_to_schema(result) if result else None
return template_complete_with_documents_model_to_schema(result) if result else None


async def get_template_by_documenso_id(
db: AsyncSession,
documenso_id: int,
) -> schemas_documents.TemplateComplete | None:
) -> schemas_documents.TemplateCompleteWithDocuments | None:
"""Return a template by its Documenso id."""

result = (
Expand All @@ -211,7 +338,7 @@ async def get_template_by_documenso_id(
.scalars()
.first()
)
return template_complete_model_to_schema(result) if result else None
return template_complete_with_documents_model_to_schema(result) if result else None


async def create_template(
Expand All @@ -225,6 +352,7 @@ async def create_template(
id=template.id,
documenso_id=template.documenso_id,
name=template.name,
recipient_id=template.recipient_id,
team_id=template.team_id,
deleted=template.deleted,
document_directory_id=template.document_directory_id,
Expand Down Expand Up @@ -259,29 +387,37 @@ async def update_template(
async def get_documents_by_user_id(
db: AsyncSession,
user_id: str,
) -> list[schemas_documents.Document]:
) -> list[schemas_documents.DocumentWithTeamInfo]:
"""Return all documents assigned to a user (without signing token)"""

result = await db.execute(
select(models_documents.DocumentDocument).where(
select(models_documents.DocumentDocument)
.where(
models_documents.DocumentDocument.user_id == user_id,
)
.options(
selectinload(models_documents.DocumentDocument.template).selectinload(
models_documents.DocumentTemplate.team,
),
),
)
return [document_model_to_schema(doc) for doc in result.scalars().all()]
return [
document_with_team_info_model_to_schema(doc) for doc in result.scalars().all()
]


async def get_documents_by_template_id(
db: AsyncSession,
template_id: UUID,
) -> list[schemas_documents.DocumentComplete]:
) -> list[schemas_documents.DocumentWithUser]:
"""Return all documents generated from a given template"""

result = await db.execute(
select(models_documents.DocumentDocument).where(
models_documents.DocumentDocument.template_id == template_id,
),
)
return [document_complete_model_to_schema(doc) for doc in result.scalars().all()]
return [document_with_user_model_to_schema(doc) for doc in result.scalars().all()]


async def get_document_by_id(
Expand Down
Loading
Loading