fachuan / apps /client /api /client_api.py
jun2024's picture
Upload 2241 files
f8b03c1 verified
Raw History Blame Contribute Delete
6.09 kB
"""
客户 API 层
只负责请求/响应处理,不包含业务逻辑
"""
from __future__ import annotations
from typing import Any, cast
from django.utils.translation import gettext_lazy as _
from ninja import File, Router, Status
from ninja.files import UploadedFile
from pydantic import BaseModel
from apps.client.schemas import ClientIn, ClientOut, ClientUpdateIn, OACredentialCheckOut
from apps.client.services.text_parser import parse_client_text as _parse_client
from apps.client.services.text_parser import parse_multiple_clients_text as _parse_multi
from apps.core.dto.request_context import extract_request_context
from apps.core.exceptions import ValidationException
from apps.core.utils.id_card_utils import IdCardUtils
class ParseTextRequest(BaseModel):
text: str
parse_multiple: bool = False
class IdCardValidateRequest(BaseModel):
id_number: str
class IdCardValidateResponse(BaseModel):
valid: bool
message: str
router = Router(tags=["Client"])
def _get_query_facade() -> Any:
"""工厂函数:创建 ClientQueryFacade 实例"""
from apps.client.services.client_query_facade import ClientQueryFacade
return ClientQueryFacade()
def _get_mutation_service() -> Any:
"""工厂函数:创建 ClientMutationService 实例"""
from apps.client.services.client_mutation_service import ClientMutationService
return ClientMutationService()
@router.get("/clients", response=list[ClientOut])
def list_clients(
request: Any,
page: int = 1,
page_size: int | None = None,
client_type: str | None = None,
is_our_client: bool | None = None,
search: str | None = None,
) -> list[ClientOut]:
"""获取客户列表"""
facade = _get_query_facade()
user = getattr(request, "auth", None) or extract_request_context(request).user
clients = facade.list_clients(
page=page,
page_size=page_size or 20,
client_type=client_type,
is_our_client=is_our_client,
search=search,
user=user,
)
return list(clients)
@router.post("/clients/parse-text")
def parse_client_text(request: Any, payload: ParseTextRequest) -> dict[str, Any]:
"""解析客户文本信息"""
if payload.parse_multiple:
results = [c for c in _parse_multi(payload.text) if c.get("name")]
return {"success": True, "clients": results}
else:
result = _parse_client(payload.text)
if result.get("name"):
return {"success": True, "client": result, "parse_method": "regex"}
else:
return {"success": False, "error": _("未能解析出客户信息")}
@router.get("/parse-text")
def parse_text_get(request: Any, text: str = "") -> dict[str, Any]:
"""解析客户文本(GET 方式)。"""
return cast(dict[str, Any], _parse_client(text))
@router.post("/clients/validate-id-card", response=IdCardValidateResponse)
def validate_id_card(request: Any, payload: IdCardValidateRequest) -> IdCardValidateResponse:
"""校验身份证号码是否合法"""
result = IdCardUtils.validate_id_card(payload.id_number)
return IdCardValidateResponse(valid=bool(result["valid"]), message=str(result["message"]))
@router.get("/clients/check-oa-credential", response=OACredentialCheckOut)
def check_oa_credential(request: Any) -> OACredentialCheckOut:
"""检查当前用户是否有金诚同达OA凭证。"""
from django.db.models import Q
from apps.organization.models import AccountCredential
lawyer_id = getattr(request.user, "id", None)
if lawyer_id is None:
return OACredentialCheckOut(has_credential=False)
credential = AccountCredential.objects.filter(
Q(account__icontains="jtn.com") | Q(url__icontains="jtn.com"),
lawyer_id=lawyer_id,
).exists()
return OACredentialCheckOut(has_credential=credential)
@router.get("/clients/{client_id}", response=ClientOut)
def get_client(request: Any, client_id: int) -> Any:
"""获取单个客户"""
facade = _get_query_facade()
user = getattr(request, "auth", None) or extract_request_context(request).user
return facade.get_client(client_id=client_id, user=user)
@router.post("/clients", response=ClientOut)
def create_client(request: Any, payload: ClientIn) -> Any:
"""创建客户"""
service = _get_mutation_service()
user = getattr(request, "auth", None) or extract_request_context(request).user
return service.create_client(data=payload.model_dump(), user=user)
@router.post("/clients-with-docs", response=ClientOut)
def create_client_with_docs(
request: Any,
payload: ClientIn,
doc_types: list[str],
files: list[UploadedFile] = File(...),
) -> Any:
"""创建客户并上传文档"""
if doc_types and files and len(doc_types) != len(files):
raise ValidationException(
message=_("证件类型数量与文件数量不一致"),
code="DOC_FILES_MISMATCH",
errors={"doc_types": _("doc_types 与 files 长度必须一致")},
)
mutation_service = _get_mutation_service()
user = getattr(request, "auth", None) or extract_request_context(request).user
return mutation_service.create_client_with_docs(
data=payload.model_dump(),
doc_types=doc_types,
files=files,
user=user,
)
@router.put("/clients/{client_id}", response=ClientOut)
def update_client(request: Any, client_id: int, payload: ClientUpdateIn) -> Any:
"""更新客户"""
service = _get_mutation_service()
data = payload.model_dump(exclude_unset=True)
user = getattr(request, "auth", None) or extract_request_context(request).user
return service.update_client(client_id=client_id, data=data, user=user)
@router.delete("/clients/{client_id}", response={204: None})
def delete_client(request: Any, client_id: int) -> Any:
"""删除客户"""
service = _get_mutation_service()
user = getattr(request, "auth", None) or extract_request_context(request).user
service.delete_client(client_id=client_id, user=user)
return Status(204, None)