You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
275 lines
8.8 KiB
Python
275 lines
8.8 KiB
Python
from __future__ import annotations
|
|
|
|
from dataclasses import dataclass
|
|
from typing import Any, Protocol
|
|
|
|
from iti.service_client import ServiceClient, service_client
|
|
|
|
from .base import (
|
|
ExchangeOperation,
|
|
ExchangeTemplateLayout,
|
|
ExchangeTemplatePlan,
|
|
ExchangeTemplateSourceKind,
|
|
ExchangeVariable,
|
|
)
|
|
|
|
|
|
class ExchangeSource(Protocol):
|
|
def resolve_plan(
|
|
self,
|
|
*,
|
|
biz_domain: str,
|
|
biz_obj: str,
|
|
operation: ExchangeOperation | str,
|
|
template_id: str | None = None,
|
|
version_id: str | None = None,
|
|
version: str | None = None,
|
|
code: str | None = None,
|
|
name: str | None = None,
|
|
description: str | None = None,
|
|
layout: ExchangeTemplateLayout | dict[str, Any] | None = None,
|
|
variables: list[ExchangeVariable] | None = None,
|
|
) -> ExchangeTemplatePlan:
|
|
...
|
|
|
|
def load_template_file(self, plan: ExchangeTemplatePlan) -> bytes | None:
|
|
...
|
|
|
|
|
|
@dataclass
|
|
class MappingExchangeSource:
|
|
def resolve_plan(
|
|
self,
|
|
*,
|
|
biz_domain: str,
|
|
biz_obj: str,
|
|
operation: ExchangeOperation | str,
|
|
template_id: str | None = None,
|
|
version_id: str | None = None,
|
|
version: str | None = None,
|
|
code: str | None = None,
|
|
name: str | None = None,
|
|
description: str | None = None,
|
|
layout: ExchangeTemplateLayout | dict[str, Any] | None = None,
|
|
variables: list[ExchangeVariable] | None = None,
|
|
) -> ExchangeTemplatePlan:
|
|
return ExchangeTemplatePlan.from_mapping(
|
|
biz_domain=biz_domain,
|
|
biz_obj=biz_obj,
|
|
operation=operation,
|
|
template_id=template_id,
|
|
version_id=version_id,
|
|
version=version,
|
|
code=code,
|
|
name=name,
|
|
description=description,
|
|
layout=layout,
|
|
variables=variables,
|
|
)
|
|
|
|
def load_template_file(self, plan: ExchangeTemplatePlan) -> bytes | None:
|
|
return _excel_template_codec().dump(plan)
|
|
|
|
|
|
@dataclass
|
|
class LocalExchangeSource:
|
|
app: Any
|
|
db: Any
|
|
|
|
def resolve_plan(
|
|
self,
|
|
*,
|
|
biz_domain: str,
|
|
biz_obj: str,
|
|
operation: ExchangeOperation | str,
|
|
template_id: str | None = None,
|
|
version_id: str | None = None,
|
|
version: str | None = None,
|
|
code: str | None = None,
|
|
name: str | None = None,
|
|
description: str | None = None,
|
|
layout: ExchangeTemplateLayout | dict[str, Any] | None = None,
|
|
variables: list[ExchangeVariable] | None = None,
|
|
) -> ExchangeTemplatePlan:
|
|
from .service import ExchangeService
|
|
|
|
return ExchangeService(self.app, self.db).resolve_plan(
|
|
biz_domain=biz_domain,
|
|
biz_obj=biz_obj,
|
|
operation=operation,
|
|
template_id=template_id,
|
|
version_id=version_id,
|
|
version=version,
|
|
code=code,
|
|
name=name,
|
|
description=description,
|
|
layout=layout,
|
|
variables=variables,
|
|
)
|
|
|
|
def load_template_file(self, plan: ExchangeTemplatePlan) -> bytes | None:
|
|
if plan.version_id:
|
|
from .service import ExchangeService
|
|
|
|
return ExchangeService(self.app, self.db).build_template_file(plan.version_id)
|
|
return _excel_template_codec().dump(plan)
|
|
|
|
|
|
@dataclass
|
|
class RemoteExchangeSource:
|
|
app: Any
|
|
service_name: str = "exchange"
|
|
|
|
def resolve_plan(
|
|
self,
|
|
*,
|
|
biz_domain: str,
|
|
biz_obj: str,
|
|
operation: ExchangeOperation | str,
|
|
template_id: str | None = None,
|
|
version_id: str | None = None,
|
|
version: str | None = None,
|
|
code: str | None = None,
|
|
name: str | None = None,
|
|
description: str | None = None,
|
|
layout: ExchangeTemplateLayout | dict[str, Any] | None = None,
|
|
variables: list[ExchangeVariable] | None = None,
|
|
) -> ExchangeTemplatePlan:
|
|
client = service_client(self.app, self.service_name)
|
|
payload = self._fetch_plan(
|
|
client,
|
|
biz_domain=biz_domain,
|
|
biz_obj=biz_obj,
|
|
operation=operation,
|
|
template_id=template_id,
|
|
version=version,
|
|
version_id=version_id,
|
|
code=code,
|
|
)
|
|
if payload is not None:
|
|
return _plan_from_mapping(payload)
|
|
return ExchangeTemplatePlan.from_mapping(
|
|
biz_domain=biz_domain,
|
|
biz_obj=biz_obj,
|
|
operation=operation,
|
|
template_id=template_id,
|
|
version_id=version_id,
|
|
version=version,
|
|
code=code,
|
|
name=name,
|
|
description=description,
|
|
layout=layout,
|
|
variables=variables,
|
|
)
|
|
|
|
def load_template_file(self, plan: ExchangeTemplatePlan) -> bytes | None:
|
|
if not plan.version_id:
|
|
return _excel_template_codec().dump(plan)
|
|
client = service_client(self.app, self.service_name)
|
|
response = client.get(
|
|
f"/exchange/template-versions/{plan.version_id}/download",
|
|
expect_json=False,
|
|
)
|
|
return response.content
|
|
|
|
def _fetch_plan(
|
|
self,
|
|
client: ServiceClient,
|
|
*,
|
|
biz_domain: str,
|
|
biz_obj: str,
|
|
operation: ExchangeOperation | str,
|
|
template_id: str | None,
|
|
version: str | None,
|
|
version_id: str | None,
|
|
code: str | None,
|
|
) -> dict[str, Any] | None:
|
|
if version_id:
|
|
return client.get(f"/exchange/template-versions/{version_id}")
|
|
if template_id and version:
|
|
return client.get(f"/exchange/templates/{template_id}/versions/by-version/{version}")
|
|
if template_id:
|
|
return client.post(
|
|
"/exchange/plans/resolve",
|
|
json={
|
|
"bizDomain": biz_domain,
|
|
"bizObj": biz_obj,
|
|
"operation": _operation_value(operation),
|
|
"templateId": template_id,
|
|
},
|
|
)
|
|
return client.post(
|
|
"/exchange/plans/resolve",
|
|
json={
|
|
"bizDomain": biz_domain,
|
|
"bizObj": biz_obj,
|
|
"operation": _operation_value(operation),
|
|
"code": code,
|
|
},
|
|
)
|
|
|
|
|
|
def _plan_from_mapping(item: dict[str, Any]) -> ExchangeTemplatePlan:
|
|
scope = item.get("scope") or {}
|
|
return ExchangeTemplatePlan.from_mapping(
|
|
biz_domain=item.get("biz_domain") or item.get("bizDomain") or scope.get("biz_domain") or scope.get("bizDomain"),
|
|
biz_obj=item.get("biz_obj") or item.get("bizObj") or scope.get("biz_obj") or scope.get("bizObj"),
|
|
operation=item.get("operation") or scope.get("operation"),
|
|
template_id=item.get("template_id") or item.get("templateId"),
|
|
version_id=item.get("version_id") or item.get("versionId") or item.get("id"),
|
|
version=item.get("version"),
|
|
code=item.get("code"),
|
|
name=item.get("name"),
|
|
description=item.get("description"),
|
|
layout=item.get("layout"),
|
|
variables=[_variable_from_mapping(value) for value in item.get("variables", [])],
|
|
)
|
|
|
|
|
|
def _variable_from_mapping(item: dict[str, Any]) -> ExchangeVariable:
|
|
return ExchangeVariable(
|
|
key=item.get("key"),
|
|
label=item.get("label") or item.get("key"),
|
|
header=item.get("header"),
|
|
description=item.get("description"),
|
|
required=bool(item.get("required", False)),
|
|
example=item.get("example"),
|
|
)
|
|
|
|
|
|
def _operation_value(value: ExchangeOperation | str) -> str:
|
|
return value.value if hasattr(value, "value") else str(value)
|
|
|
|
|
|
def _excel_template_codec():
|
|
from .excel import ExcelTemplateCodec
|
|
|
|
return ExcelTemplateCodec()
|
|
|
|
|
|
def get_exchange_source(
|
|
app: Any,
|
|
*,
|
|
source_kind: ExchangeTemplateSourceKind | str = ExchangeTemplateSourceKind.MAPPING,
|
|
source_name: str | None = None,
|
|
db: Any | None = None,
|
|
service_name: str = "exchange",
|
|
) -> ExchangeSource:
|
|
if source_name:
|
|
from .registry import get_exchange_registry
|
|
|
|
source = get_exchange_registry(app).get_source(source_name)
|
|
if source is None:
|
|
raise ValueError(f"exchange source not registered: {source_name}")
|
|
return source # type: ignore[return-value]
|
|
kind = ExchangeTemplateSourceKind(source_kind)
|
|
if kind == ExchangeTemplateSourceKind.LOCAL:
|
|
if db is None:
|
|
raise ValueError("local exchange source requires db")
|
|
return LocalExchangeSource(app=app, db=db)
|
|
if kind == ExchangeTemplateSourceKind.REMOTE:
|
|
return RemoteExchangeSource(app=app, service_name=service_name)
|
|
if kind == ExchangeTemplateSourceKind.CUSTOM:
|
|
raise ValueError("custom exchange source requires source_name")
|
|
return MappingExchangeSource()
|