Files
company-ai-platform/app/modules/writebacks/adapters.py
JiuContinent 19e59e83cc ```
feat: 添加数据库迁移脚本并更新Dockerfile配置

- 在Dockerfile中添加alembic配置文件和目录的复制指令
- 更新alembic/env.py注册新的模块模型:events、workflows、writebacks
- 生成完整的初始数据库schema迁移脚本,包含以下表:
  - approval_requests, attendance_records, audit_logs, domain_events
  - expenses, feishu_event_receipts, fund_accounts, legacy_sync_runs
  - official_writeback_runs, performance_metrics, policies, procurements
  - projects, report_push_runs, risk_event_actions, risk_events
  - standards, suppliers, work_reports, work_tasks, workflow_actions
  - workflow_instances等21个数据表结构定义
- 在API路由器中添加新模块的路由:events、workflows、writebacks、observability
```
2026-07-08 14:08:03 +08:00

75 lines
2.7 KiB
Python

from typing import Any, Protocol
import httpx
from fastapi import HTTPException, status
from app.core.config import Settings
from app.core.constants import BEARER_TOKEN_TEMPLATE, HttpHeader
from app.modules.writebacks.constants import (
WRITEBACK_DISABLED_MESSAGE,
WritebackErrorDetail,
WritebackPayloadKey,
WritebackStatus,
)
from app.modules.writebacks.models import OfficialWritebackRun
class WritebackAdapter(Protocol):
def submit(self, run: OfficialWritebackRun) -> dict[str, Any]:
"""Submit one writeback run to the configured official integration."""
class DisabledWritebackAdapter:
def submit(self, run: OfficialWritebackRun) -> dict[str, Any]:
return {
WritebackPayloadKey.STATUS: WritebackStatus.DISABLED,
WritebackPayloadKey.ERROR_MESSAGE: WRITEBACK_DISABLED_MESSAGE,
WritebackPayloadKey.CODE: run.code,
}
class HttpWritebackAdapter:
def __init__(self, settings: Settings):
self.settings = settings
def submit(self, run: OfficialWritebackRun) -> dict[str, Any]:
if not self.settings.official_api_base_url or not self.settings.official_api_token:
raise HTTPException(
status_code=status.HTTP_503_SERVICE_UNAVAILABLE,
detail=WritebackErrorDetail.OFFICIAL_API_NOT_CONFIGURED,
)
url = f"{self.settings.official_api_base_url.rstrip('/')}/writebacks/{run.domain}"
headers = {
HttpHeader.AUTHORIZATION: BEARER_TOKEN_TEMPLATE.format(
token=self.settings.official_api_token
)
}
payload = {
WritebackPayloadKey.CODE: run.code,
WritebackPayloadKey.DOMAIN: run.domain,
WritebackPayloadKey.RECORD_ID: run.record_id,
WritebackPayloadKey.ACTION: run.action,
WritebackPayloadKey.PAYLOAD: run.request_payload or {},
}
with httpx.Client(timeout=self.settings.official_api_timeout_seconds) as client:
response = client.post(url, json=payload, headers=headers)
if response.status_code >= status.HTTP_400_BAD_REQUEST:
raise HTTPException(
status_code=status.HTTP_502_BAD_GATEWAY,
detail=response.text,
)
try:
data = response.json()
except ValueError:
data = {"text": response.text}
return {
WritebackPayloadKey.STATUS: WritebackStatus.SENT,
WritebackPayloadKey.PROVIDER_RESPONSE: data,
}
def get_writeback_adapter(settings: Settings) -> WritebackAdapter:
if settings.official_writeback_enabled:
return HttpWritebackAdapter(settings)
return DisabledWritebackAdapter()