Initial commit from monorepo
This commit is contained in:
3
kyc_app/temporal/__init__.py
Normal file
3
kyc_app/temporal/__init__.py
Normal file
@@ -0,0 +1,3 @@
|
||||
from .kyc_workflow_client import KycWorkflowClient
|
||||
|
||||
__all__ = ["KycWorkflowClient"]
|
||||
117
kyc_app/temporal/kyc_workflow_client.py
Normal file
117
kyc_app/temporal/kyc_workflow_client.py
Normal file
@@ -0,0 +1,117 @@
|
||||
"""
|
||||
KYC Workflow Client - контракт взаимодействия с Temporal KYC workflow.
|
||||
|
||||
Этот файл содержит методы для запуска KYC workflow из Django.
|
||||
Approve/reject сигналы отправляются из Odoo.
|
||||
"""
|
||||
|
||||
import asyncio
|
||||
import logging
|
||||
from dataclasses import dataclass, field
|
||||
from typing import Optional
|
||||
|
||||
from django.conf import settings
|
||||
from temporalio.client import Client
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
@dataclass
|
||||
class KycWorkflowData:
|
||||
"""Данные для запуска KYC workflow."""
|
||||
|
||||
kyc_request_id: str
|
||||
team_name: str
|
||||
owner_id: str
|
||||
owner_email: str
|
||||
country_code: str
|
||||
country_data: dict = field(default_factory=dict)
|
||||
# team_id создаётся в workflow после approve, не передаётся сюда
|
||||
|
||||
|
||||
class KycWorkflowClient:
|
||||
"""
|
||||
Клиент для запуска KYC Application workflow.
|
||||
|
||||
Использование:
|
||||
KycWorkflowClient.start(kyc_request)
|
||||
|
||||
Flow:
|
||||
1. Django вызывает start() → запускает workflow
|
||||
2. Workflow добавляет KYC в Odoo, ставит статус KYC_IN_REVIEW
|
||||
3. Workflow ждёт сигнала approve/reject (из Odoo)
|
||||
4. После approve → создаёт Logto org, ставит ACTIVE
|
||||
"""
|
||||
|
||||
WORKFLOW_NAME = "kyc_application"
|
||||
|
||||
@classmethod
|
||||
async def _get_client(cls) -> Client:
|
||||
"""Получить подключение к Temporal."""
|
||||
return await Client.connect(
|
||||
settings.TEMPORAL_HOST,
|
||||
namespace=settings.TEMPORAL_NAMESPACE,
|
||||
)
|
||||
|
||||
@classmethod
|
||||
async def start_async(cls, data: KycWorkflowData) -> str:
|
||||
"""
|
||||
Запустить KYC Application workflow (async).
|
||||
|
||||
Returns:
|
||||
workflow_id: ID запущенного workflow
|
||||
"""
|
||||
client = await cls._get_client()
|
||||
|
||||
workflow_id = data.kyc_request_id
|
||||
|
||||
await client.start_workflow(
|
||||
cls.WORKFLOW_NAME,
|
||||
{
|
||||
"kyc_request_id": data.kyc_request_id,
|
||||
"team_name": data.team_name,
|
||||
"owner_id": data.owner_id,
|
||||
"owner_email": data.owner_email,
|
||||
"country_code": data.country_code,
|
||||
"country_data": data.country_data,
|
||||
},
|
||||
id=workflow_id,
|
||||
task_queue=settings.TEMPORAL_TASK_QUEUE,
|
||||
)
|
||||
|
||||
logger.info(f"KYC workflow started: {workflow_id}")
|
||||
return workflow_id
|
||||
|
||||
@classmethod
|
||||
def start(cls, kyc_request) -> Optional[str]:
|
||||
"""
|
||||
Запустить KYC Application workflow (sync wrapper).
|
||||
|
||||
Args:
|
||||
kyc_request: KYCRequest model instance (главная модель)
|
||||
|
||||
Returns:
|
||||
workflow_id или None при ошибке
|
||||
"""
|
||||
# Собираем данные страны через GenericForeignKey
|
||||
country_data = kyc_request.get_country_data()
|
||||
|
||||
data = KycWorkflowData(
|
||||
kyc_request_id=str(kyc_request.uuid),
|
||||
team_name=kyc_request.team_name or country_data.get('company_name', ''),
|
||||
owner_id=kyc_request.user_id,
|
||||
owner_email=kyc_request.contact_email,
|
||||
country_code=kyc_request.country_code,
|
||||
country_data=country_data,
|
||||
)
|
||||
|
||||
try:
|
||||
workflow_id = asyncio.run(cls.start_async(data))
|
||||
kyc_request.workflow_status = "active"
|
||||
kyc_request.save(update_fields=["workflow_status", "updated_at"])
|
||||
return workflow_id
|
||||
except Exception as e:
|
||||
logger.error(f"Failed to start KYC workflow: {e}")
|
||||
kyc_request.workflow_status = "error"
|
||||
kyc_request.save(update_fields=["workflow_status", "updated_at"])
|
||||
return None
|
||||
Reference in New Issue
Block a user