fc / apps /cases /services /case /case_internal_query_service.py
jun2024's picture
Upload 2241 files
b4f2238 verified
Raw History Blame Contribute Delete
7.11 kB
"""Business logic services."""
from __future__ import annotations
import logging
from typing import TYPE_CHECKING
from apps.core.exceptions import NotFoundError
from .assembler import CaseDtoAssembler
from .case_query_orchestrator import (
CaseAccessQueryOrchestrator,
CaseNumberQueryOrchestrator,
CasePartyQueryOrchestrator,
CaseQueryOrchestrator,
)
from .repo import CaseRepo, CaseSearchRepo
if TYPE_CHECKING:
from apps.core.interfaces import CaseDTO
logger = logging.getLogger("apps.cases")
class CaseInternalQueryService:
_MISSING_SENTINEL = "__case_access_grants_missing__"
def __init__(
self,
orchestrator: CaseQueryOrchestrator | None = None,
case_repo: CaseRepo | None = None,
case_search_repo: CaseSearchRepo | None = None,
case_number_orchestrator: CaseNumberQueryOrchestrator | None = None,
case_party_orchestrator: CasePartyQueryOrchestrator | None = None,
case_access_orchestrator: CaseAccessQueryOrchestrator | None = None,
assembler: CaseDtoAssembler | None = None,
) -> None:
self._orchestrator = orchestrator
self._orchestrator_kwargs = {
"case_repo": case_repo,
"case_search_repo": case_search_repo,
"case_number_orchestrator": case_number_orchestrator,
"case_party_orchestrator": case_party_orchestrator,
"case_access_orchestrator": case_access_orchestrator,
"assembler": assembler,
}
@property
def orchestrator(self) -> CaseQueryOrchestrator:
if self._orchestrator is None:
self._orchestrator = CaseQueryOrchestrator(**self._orchestrator_kwargs) # type: ignore
return self._orchestrator
def get_case_internal(self, case_id: int) -> CaseDTO | None:
try:
return self.orchestrator.get_case(case_id)
except NotFoundError:
return None
except Exception:
logger.exception("get_case_internal_failed", extra={"case_id": case_id})
raise
def get_cases_by_contract_internal(self, contract_id: int) -> list[CaseDTO]:
return self.orchestrator.get_cases_by_contract(contract_id)
def get_cases_by_ids_internal(self, case_ids: list[int]) -> list[CaseDTO]:
return self.orchestrator.get_cases_by_ids(case_ids)
def validate_case_active_internal(self, case_id: int) -> bool:
return self.orchestrator.validate_case_active(case_id)
def get_case_current_stage_internal(self, case_id: int) -> str | None:
return self.orchestrator.get_case_current_stage(case_id)
def check_case_access_internal(self, case_id: int, user_id: int) -> bool:
return self.orchestrator.check_case_access(case_id, user_id)
def get_primary_lawyer_names_by_case_ids_internal(self, case_ids: list[int]) -> dict[int, str | None]:
return self.orchestrator.get_primary_lawyer_names_by_case_ids(case_ids)
def get_primary_case_numbers_by_case_ids_internal(self, case_ids: list[int]) -> dict[int, str | None]:
return self.orchestrator.get_primary_case_numbers_by_case_ids(case_ids)
def get_user_extra_case_access_internal(self, user_id: int) -> list[int]:
from django.core.cache import cache
from apps.core.infrastructure import CacheKeys, CacheTimeout
cache_key = CacheKeys.case_access_grants(user_id)
cached = cache.get(cache_key)
if cached is not None:
if cached == self._MISSING_SENTINEL:
return []
return list(cached or [])
try:
result = list(self.orchestrator.get_user_extra_case_access(user_id) or [])
cache.set(cache_key, result, timeout=CacheTimeout.get_medium())
return result
except Exception:
logger.exception("get_user_extra_case_access_internal_failed", extra={"user_id": user_id})
raise
def search_cases_by_party_internal(self, party_names: list[str], status: str | None = None) -> list[CaseDTO]:
return self.orchestrator.search_cases_by_party(party_names, status=status)
def search_cases_for_binding_internal(self, search_term: str = "", limit: int = 20) -> list[dict[str, object]]:
"""搜索可绑定的案件(含案号和当事人信息)
支持按案件名称、案号、当事人搜索.
search_term: 搜索关键词
limit: 返回数量限制
案件信息字典列表
"""
from django.db.models import Q
from apps.cases.models import Case, CaseNumber, CaseParty
limit = min(limit, 20)
if not search_term or not search_term.strip():
cases = (
Case.objects.select_related()
.prefetch_related("case_numbers", "parties__client")
.order_by("-id")[:limit]
)
else:
term = search_term.strip()
name_query = Q(name__icontains=term)
case_ids_by_number = CaseNumber.objects.filter(
number__icontains=term,
).values_list("case_id", flat=True)
case_ids_by_party = CaseParty.objects.filter(
client__name__icontains=term,
).values_list("case_id", flat=True)
cases = (
Case.objects.filter(
name_query | Q(id__in=case_ids_by_number) | Q(id__in=case_ids_by_party),
)
.select_related()
.prefetch_related("case_numbers", "parties__client")
.distinct()
.order_by("-id")[:limit]
)
results: list[dict[str, object]] = []
for case in cases:
case_numbers = [cn.number for cn in case.case_numbers.all()]
parties = [p.client.name for p in case.parties.all() if p.client]
results.append(
{
"id": case.id,
"name": case.name,
"case_numbers": case_numbers,
"parties": parties,
"created_at": case.start_date.isoformat() if case.start_date else None,
}
)
return results
def get_case_numbers_by_case_internal(self, case_id: int) -> list[str]:
return self.orchestrator.get_case_numbers_by_case(case_id)
def get_case_party_names_internal(self, case_id: int) -> list[str]:
return self.orchestrator.get_case_party_names(case_id)
def search_cases_by_case_number_internal(self, case_number: str) -> list[CaseDTO]:
return self.orchestrator.search_cases_by_case_number(case_number)
def list_cases_internal(
self, status: str | None = None, limit: int | None = None, order_by: str = "-start_date"
) -> list[CaseDTO]:
return self.orchestrator.list_cases(status=status, limit=limit, order_by=order_by)
def search_cases_internal(self, query: str, status: str | None = None, limit: int = 30) -> list[CaseDTO]:
return self.orchestrator.search_cases(query=query, status=status, limit=limit)