增加了项目侧关于steps的处理。允许保存和提取steps信息。
This commit is contained in:
@@ -21,7 +21,7 @@ class CompanySyncStrategy(DefaultSyncStrategy[CompanyResponse]):
|
||||
# 类变量:默认配置
|
||||
default_config = StrategyConfig(
|
||||
auto_bind=True,
|
||||
auto_bind_fields=["credit_code"],
|
||||
auto_bind_fields=["code"],
|
||||
depend_fields={},
|
||||
local_orphan_action=OrphanAction.NONE,
|
||||
remote_orphan_action=OrphanAction.CREATE_LOCAL,
|
||||
|
||||
@@ -81,7 +81,12 @@ class ConstructionTaskApiHandler(BaseApiHandler):
|
||||
results.append(TaskResult.failed(node_id=node.node_id, error=f"{ERROR_VALIDATION_FAILED}: {e}"))
|
||||
continue
|
||||
|
||||
response = await api_create_construction_task(self.api_client, create_model, push_id)
|
||||
response = await api_create_construction_task(
|
||||
self.api_client,
|
||||
create_model,
|
||||
push_id,
|
||||
steps=self._get_request_steps(node),
|
||||
)
|
||||
if self.poll_mode == "sync":
|
||||
created_id = self._extract_created_id_from_response(response)
|
||||
if not created_id:
|
||||
@@ -134,8 +139,13 @@ class ConstructionTaskApiHandler(BaseApiHandler):
|
||||
|
||||
# 1. 基础信息更新 (ConstructionUpdate)
|
||||
# 业务逻辑:如果 show_name 字段不同,那么仅当 type == 'QT' 时才更新
|
||||
force_steps_update = self._steps_changed(node)
|
||||
steps_payload = self._get_request_steps(node)
|
||||
steps_sent = False
|
||||
base_new_schema_error = self._validate_schema(data, ConstructionUpdate)
|
||||
base_changed_fields = self._schema_changed_fields(ConstructionUpdate, data, origin_data)
|
||||
if force_steps_update and not base_new_schema_error and not base_changed_fields:
|
||||
base_changed_fields = ["__steps__"]
|
||||
base_update_called = False
|
||||
base_update_error: str | None = None
|
||||
if base_new_schema_error:
|
||||
@@ -150,11 +160,29 @@ class ConstructionTaskApiHandler(BaseApiHandler):
|
||||
|
||||
if should_update:
|
||||
try:
|
||||
update_model = ConstructionUpdate.model_validate(data)
|
||||
update_payload = data if (force_steps_update and base_changed_fields == ["__steps__"]) else data
|
||||
update_model = ConstructionUpdate.model_validate(update_payload)
|
||||
push_id = self._generate_push_id()
|
||||
await api_update_construction_task(self.api_client, update_model, push_id, biz_id)
|
||||
request_steps = steps_payload if not steps_sent else []
|
||||
if request_steps:
|
||||
await api_update_construction_task(
|
||||
self.api_client,
|
||||
update_model,
|
||||
push_id,
|
||||
biz_id,
|
||||
steps=request_steps,
|
||||
)
|
||||
else:
|
||||
await api_update_construction_task(
|
||||
self.api_client,
|
||||
update_model,
|
||||
push_id,
|
||||
biz_id,
|
||||
)
|
||||
node_updated = True
|
||||
base_update_called = True
|
||||
steps_sent = steps_sent or bool(steps_payload)
|
||||
self._mark_approval_snapshot_synced(node)
|
||||
except Exception as e:
|
||||
error = str(e)
|
||||
base_update_error = str(e)
|
||||
@@ -185,9 +213,26 @@ class ConstructionTaskApiHandler(BaseApiHandler):
|
||||
plan_model = ConstructionPlanUpdate.model_validate(data)
|
||||
plan_dict = plan_model.model_dump(exclude_unset=True)
|
||||
push_id = self._generate_push_id()
|
||||
await api_update_construction_task_plan(self.api_client, plan_dict, push_id, biz_id)
|
||||
request_steps = steps_payload if not steps_sent else []
|
||||
if request_steps:
|
||||
await api_update_construction_task_plan(
|
||||
self.api_client,
|
||||
plan_dict,
|
||||
push_id,
|
||||
biz_id,
|
||||
steps=request_steps,
|
||||
)
|
||||
else:
|
||||
await api_update_construction_task_plan(
|
||||
self.api_client,
|
||||
plan_dict,
|
||||
push_id,
|
||||
biz_id,
|
||||
)
|
||||
node_updated = True
|
||||
plan_update_called = True
|
||||
steps_sent = steps_sent or bool(steps_payload)
|
||||
self._mark_approval_snapshot_synced(node)
|
||||
except Exception as e:
|
||||
error = str(e)
|
||||
plan_update_error = str(e)
|
||||
@@ -279,16 +324,23 @@ async def api_get_construction_task_list(client, project_id: str) -> List[Constr
|
||||
return validated_items
|
||||
|
||||
|
||||
async def api_create_construction_task(client, data: ConstructionCreate, push_id: str) -> Dict[str, Any]:
|
||||
request_data = {"push_id": push_id, "data": data.model_dump()}
|
||||
async def api_create_construction_task(client, data: ConstructionCreate, push_id: str, *, steps: List[Dict[str, Any]] | None = None) -> Dict[str, Any]:
|
||||
request_data = {"push_id": push_id, "data": data.model_dump(), "steps": steps or []}
|
||||
response = await client.request(method="POST", endpoint="/construction/create", data=request_data)
|
||||
if response.get("code") != 200:
|
||||
raise Exception(f"API error: {response.get('message', 'Unknown error')}")
|
||||
return response
|
||||
|
||||
|
||||
async def api_update_construction_task(client, data: ConstructionUpdate, push_id: str, biz_id: str) -> None:
|
||||
request_data = {"push_id": push_id, "biz_id": biz_id, "data": data.model_dump(exclude_unset=True)}
|
||||
async def api_update_construction_task(
|
||||
client,
|
||||
data: ConstructionUpdate,
|
||||
push_id: str,
|
||||
biz_id: str,
|
||||
*,
|
||||
steps: List[Dict[str, Any]] | None = None,
|
||||
) -> None:
|
||||
request_data = {"push_id": push_id, "biz_id": biz_id, "data": data.model_dump(exclude_unset=True), "steps": steps or []}
|
||||
response = await client.request(method="PUT", endpoint="/construction/update", data=request_data)
|
||||
if response.get("code") != 200:
|
||||
raise Exception(f"API error: {response.get('message', 'Unknown error')}")
|
||||
@@ -306,9 +358,16 @@ async def api_get_construction_task(client, task_id: str) -> Dict[str, Any]:
|
||||
return response.get("data", {})
|
||||
|
||||
|
||||
async def api_update_construction_task_plan(client, data: Dict[str, Any], push_id: str, biz_id: str) -> None:
|
||||
async def api_update_construction_task_plan(
|
||||
client,
|
||||
data: Dict[str, Any],
|
||||
push_id: str,
|
||||
biz_id: str,
|
||||
*,
|
||||
steps: List[Dict[str, Any]] | None = None,
|
||||
) -> None:
|
||||
"""PUT /construction/plan - 更新施工计划"""
|
||||
request_data = {"push_id": push_id, "biz_id": biz_id, "data": data}
|
||||
request_data = {"push_id": push_id, "biz_id": biz_id, "data": data, "steps": steps or []}
|
||||
response = await client.request(method="PUT", endpoint="/construction/plan", data=request_data)
|
||||
if response.get("code") != 200:
|
||||
raise Exception(f"API error: {response.get('message', 'Unknown error')}")
|
||||
|
||||
@@ -78,7 +78,12 @@ class ConstructionTaskDetailApiHandler(BaseApiHandler):
|
||||
push_id = self._generate_push_id()
|
||||
|
||||
try:
|
||||
response = await api_create_construction_task_detail(self.api_client, create_model, push_id)
|
||||
response = await api_create_construction_task_detail(
|
||||
self.api_client,
|
||||
create_model,
|
||||
push_id,
|
||||
steps=self._get_request_steps(node),
|
||||
)
|
||||
if self.poll_mode == "sync":
|
||||
created_id = self._extract_created_id_from_response(response)
|
||||
if not created_id:
|
||||
@@ -120,7 +125,14 @@ class ConstructionTaskDetailApiHandler(BaseApiHandler):
|
||||
origin_data = node.get_origin_data() or {}
|
||||
|
||||
# 使用 _get_schema_diff 检查差异并打印日志
|
||||
diff_fields = self._get_schema_diff(ConstructionDetailUpdate, data, origin_data, node.node_id)
|
||||
force_steps_update = self._steps_changed(node)
|
||||
diff_fields = self._get_schema_diff(
|
||||
ConstructionDetailUpdate,
|
||||
data,
|
||||
origin_data,
|
||||
node.node_id,
|
||||
force_full_schema=force_steps_update,
|
||||
)
|
||||
if not diff_fields:
|
||||
from ...common.types import SyncAction
|
||||
results.append(TaskResult.skipped(node_id=node.node_id, reason="No updatable fields changed"))
|
||||
@@ -133,7 +145,12 @@ class ConstructionTaskDetailApiHandler(BaseApiHandler):
|
||||
continue
|
||||
|
||||
# 需要完整的 schema 数据(包括必填字段)
|
||||
update_data = self._filter_update_data(data, origin_data, ConstructionDetailUpdate)
|
||||
update_data = self._filter_update_data(
|
||||
data,
|
||||
origin_data,
|
||||
ConstructionDetailUpdate,
|
||||
force_full_schema=force_steps_update,
|
||||
)
|
||||
|
||||
# 验证并转换为 Pydantic model
|
||||
try:
|
||||
@@ -148,6 +165,7 @@ class ConstructionTaskDetailApiHandler(BaseApiHandler):
|
||||
|
||||
# 准备批量数据
|
||||
detail_list = [model.model_dump(mode='json', exclude_unset=True) for node, model in group_items]
|
||||
steps = self._get_request_steps(group_items[0][0]) if group_items else []
|
||||
|
||||
# 使用 parent_id(task_id)作为 biz_id
|
||||
biz_id = task_id
|
||||
@@ -159,9 +177,11 @@ class ConstructionTaskDetailApiHandler(BaseApiHandler):
|
||||
{"detail_list": detail_list},
|
||||
push_id,
|
||||
biz_id,
|
||||
steps=steps,
|
||||
)
|
||||
# 整组成功
|
||||
for node, _ in group_items:
|
||||
self._mark_approval_snapshot_synced(node)
|
||||
if self.poll_mode == "sync":
|
||||
results.append(TaskResult.success(node_id=node.node_id))
|
||||
else:
|
||||
@@ -243,7 +263,13 @@ async def api_get_construction_task_detail_list(client, task_id: str) -> List[Co
|
||||
return validated_items
|
||||
|
||||
|
||||
async def api_create_construction_task_detail(client, data: ConstructionDetailCreate, push_id: str) -> Dict[str, Any]:
|
||||
async def api_create_construction_task_detail(
|
||||
client,
|
||||
data: ConstructionDetailCreate,
|
||||
push_id: str,
|
||||
*,
|
||||
steps: List[Dict[str, Any]] | None = None,
|
||||
) -> Dict[str, Any]:
|
||||
"""
|
||||
创建施工明细 POST /construction/detail/create
|
||||
|
||||
@@ -253,14 +279,21 @@ async def api_create_construction_task_detail(client, data: ConstructionDetailCr
|
||||
push_id: 推送ID
|
||||
biz_id: 业务ID
|
||||
"""
|
||||
request_data = {"push_id": push_id, "data": data.model_dump(mode='json')}
|
||||
request_data = {"push_id": push_id, "data": data.model_dump(mode='json'), "steps": steps or []}
|
||||
response = await client.request(method="POST", endpoint="/construction/detail/create", data=request_data)
|
||||
if response.get("code") != 200:
|
||||
raise Exception(f"API error: {response.get('message', 'Unknown error')}")
|
||||
return response
|
||||
|
||||
|
||||
async def api_update_construction_task_detail(client, data: Dict[str, Any], push_id: str, biz_id: str) -> None:
|
||||
async def api_update_construction_task_detail(
|
||||
client,
|
||||
data: Dict[str, Any],
|
||||
push_id: str,
|
||||
biz_id: str,
|
||||
*,
|
||||
steps: List[Dict[str, Any]] | None = None,
|
||||
) -> None:
|
||||
"""
|
||||
更新施工明细 PUT /construction/detail/update
|
||||
|
||||
@@ -270,7 +303,7 @@ async def api_update_construction_task_detail(client, data: Dict[str, Any], push
|
||||
push_id: 推送ID
|
||||
biz_id: 业务ID
|
||||
"""
|
||||
request_data = {"push_id": push_id, "biz_id": biz_id, "data": data}
|
||||
request_data = {"push_id": push_id, "biz_id": biz_id, "data": data, "steps": steps or []}
|
||||
response = await client.request(method="PUT", endpoint="/construction/detail/update", data=request_data)
|
||||
if response.get("code") != 200:
|
||||
raise Exception(f"API error: {response.get('message', 'Unknown error')}")
|
||||
|
||||
@@ -48,20 +48,38 @@ async def api_get_contract(client: ApiClient, contract_id: str) -> ContractRespo
|
||||
return ContractResponse.model_validate(response["data"])
|
||||
|
||||
|
||||
async def api_create_contract(client: ApiClient, data: Dict[str, Any], push_id: str) -> Dict[str, Any]:
|
||||
async def api_create_contract(
|
||||
client: ApiClient,
|
||||
data: Dict[str, Any],
|
||||
push_id: str,
|
||||
*,
|
||||
steps: List[Dict[str, Any]] | None = None,
|
||||
) -> Dict[str, Any]:
|
||||
"""POST /contract/create - 创建合同(异步)"""
|
||||
validated_data = ContractCreate.model_validate(data)
|
||||
request_data = {"push_id": push_id, "data": validated_data.model_dump(exclude_none=True)}
|
||||
request_data = {"push_id": push_id, "data": validated_data.model_dump(exclude_none=True), "steps": steps or []}
|
||||
response = await client.request("POST", "/contract/create", data=request_data)
|
||||
if response.get("code") != 200:
|
||||
raise Exception(f"Failed to create contract: {response.get('message', 'Unknown error')}")
|
||||
return response
|
||||
|
||||
|
||||
async def api_update_contract(client: ApiClient, data_id: str, data: Dict[str, Any], push_id: str) -> Dict[str, Any]:
|
||||
async def api_update_contract(
|
||||
client: ApiClient,
|
||||
data_id: str,
|
||||
data: Dict[str, Any],
|
||||
push_id: str,
|
||||
*,
|
||||
steps: List[Dict[str, Any]] | None = None,
|
||||
) -> Dict[str, Any]:
|
||||
"""PUT /contract/update - 更新合同(同步)"""
|
||||
validated_data = ContractUpdate.model_validate(data)
|
||||
request_data = {"push_id": push_id, "biz_id": data_id, "data": validated_data.model_dump(exclude_none=True)}
|
||||
request_data = {
|
||||
"push_id": push_id,
|
||||
"biz_id": data_id,
|
||||
"data": validated_data.model_dump(exclude_none=True),
|
||||
"steps": steps or [],
|
||||
}
|
||||
response = await client.request("PUT", "/contract/update", data=request_data)
|
||||
if response.get("code") != 200:
|
||||
raise Exception(f"Failed to update contract: {response.get('message', 'Unknown error')}")
|
||||
@@ -194,7 +212,12 @@ class ContractApiHandler(BaseApiHandler):
|
||||
|
||||
# 调用 API(直接调用顶层函数)
|
||||
push_id = self._generate_push_id()
|
||||
response = await api_create_contract(self.api_client, request_data, push_id)
|
||||
response = await api_create_contract(
|
||||
self.api_client,
|
||||
request_data,
|
||||
push_id,
|
||||
steps=self._get_request_steps(node),
|
||||
)
|
||||
if self.poll_mode == "sync":
|
||||
created_id = self._extract_created_id_from_response(response)
|
||||
if not created_id:
|
||||
@@ -232,10 +255,12 @@ class ContractApiHandler(BaseApiHandler):
|
||||
|
||||
# 过滤出需要更新的字段(排除空值、未变化的字段)
|
||||
origin_data = node.get_origin_data() or {}
|
||||
force_steps_update = self._steps_changed(node)
|
||||
update_data = self._filter_update_data(
|
||||
new_data=data,
|
||||
original_data=origin_data,
|
||||
schema=ContractUpdate,
|
||||
force_full_schema=force_steps_update,
|
||||
)
|
||||
|
||||
# 如果没有需要更新的字段,降级 action 并返回跳过
|
||||
@@ -257,10 +282,17 @@ class ContractApiHandler(BaseApiHandler):
|
||||
return TaskResult.failed(node_id=node.node_id, error="Missing biz_id for update")
|
||||
|
||||
# 调用 API
|
||||
response = await api_update_contract(self.api_client, biz_id, update_data, push_id)
|
||||
response = await api_update_contract(
|
||||
self.api_client,
|
||||
biz_id,
|
||||
update_data,
|
||||
push_id,
|
||||
steps=self._get_request_steps(node),
|
||||
)
|
||||
|
||||
# 检查响应状态(更新接口是同步的)
|
||||
if response.get("code") == 200:
|
||||
self._mark_approval_snapshot_synced(node)
|
||||
return TaskResult.success(node_id=node.node_id)
|
||||
else:
|
||||
return TaskResult.failed(
|
||||
|
||||
@@ -55,7 +55,12 @@ class ContractChangeApiHandler(BaseApiHandler):
|
||||
push_id = self._generate_push_id()
|
||||
|
||||
try:
|
||||
response = await api_create_contract_change(self.api_client, create_model, push_id)
|
||||
response = await api_create_contract_change(
|
||||
self.api_client,
|
||||
create_model,
|
||||
push_id,
|
||||
steps=self._get_request_steps(node),
|
||||
)
|
||||
if self.poll_mode == "sync":
|
||||
created_id = self._extract_created_id_from_response(response)
|
||||
if not created_id:
|
||||
@@ -87,7 +92,13 @@ class ContractChangeApiHandler(BaseApiHandler):
|
||||
continue
|
||||
|
||||
origin_data = node.get_origin_data() or {}
|
||||
update_data = self._filter_update_data(node_data, origin_data, PostContractChange)
|
||||
force_steps_update = self._steps_changed(node)
|
||||
update_data = self._filter_update_data(
|
||||
node_data,
|
||||
origin_data,
|
||||
PostContractChange,
|
||||
force_full_schema=force_steps_update,
|
||||
)
|
||||
if not update_data:
|
||||
from ...common.types import SyncAction
|
||||
results.append(TaskResult.skipped(node_id=node.node_id, reason="No updatable fields changed"))
|
||||
@@ -107,7 +118,14 @@ class ContractChangeApiHandler(BaseApiHandler):
|
||||
continue
|
||||
|
||||
try:
|
||||
await api_update_contract_change(self.api_client, update_model, push_id, biz_id)
|
||||
await api_update_contract_change(
|
||||
self.api_client,
|
||||
update_model,
|
||||
push_id,
|
||||
biz_id,
|
||||
steps=self._get_request_steps(node),
|
||||
)
|
||||
self._mark_approval_snapshot_synced(node)
|
||||
results.append(TaskResult.success(node_id=node.node_id))
|
||||
except Exception as e:
|
||||
results.append(TaskResult.failed(node_id=node.node_id, error=str(e)))
|
||||
@@ -138,7 +156,13 @@ class ContractChangeApiHandler(BaseApiHandler):
|
||||
|
||||
# ========== 静态 API 函数 ==========
|
||||
|
||||
async def api_create_contract_change(client, data: CreateContractChange, push_id: str) -> Dict[str, Any]:
|
||||
async def api_create_contract_change(
|
||||
client,
|
||||
data: CreateContractChange,
|
||||
push_id: str,
|
||||
*,
|
||||
steps: List[Dict[str, Any]] | None = None,
|
||||
) -> Dict[str, Any]:
|
||||
"""
|
||||
POST /contract_change/create - 创建合同变更
|
||||
|
||||
@@ -148,14 +172,21 @@ async def api_create_contract_change(client, data: CreateContractChange, push_id
|
||||
push_id: 推送ID
|
||||
biz_id: 业务ID
|
||||
"""
|
||||
request_data = {"push_id": push_id, "data": data.model_dump()}
|
||||
request_data = {"push_id": push_id, "data": data.model_dump(), "steps": steps or []}
|
||||
response = await client.request(method="POST", endpoint="/contract_change/create", data=request_data)
|
||||
if response.get("code") != 200:
|
||||
raise Exception(f"API error: {response.get('message', 'Unknown error')}")
|
||||
return response
|
||||
|
||||
|
||||
async def api_update_contract_change(client, data: PostContractChange, push_id: str, biz_id: str) -> None:
|
||||
async def api_update_contract_change(
|
||||
client,
|
||||
data: PostContractChange,
|
||||
push_id: str,
|
||||
biz_id: str,
|
||||
*,
|
||||
steps: List[Dict[str, Any]] | None = None,
|
||||
) -> None:
|
||||
"""
|
||||
PUT /contract_change/update - 更新合同变更
|
||||
|
||||
@@ -165,7 +196,7 @@ async def api_update_contract_change(client, data: PostContractChange, push_id:
|
||||
push_id: 推送ID
|
||||
biz_id: 业务ID
|
||||
"""
|
||||
request_data = {"push_id": push_id, "biz_id": biz_id, "data": data.model_dump(exclude_unset=True)}
|
||||
request_data = {"push_id": push_id, "biz_id": biz_id, "data": data.model_dump(exclude_unset=True), "steps": steps or []}
|
||||
response = await client.request(method="PUT", endpoint="/contract_change/update", data=request_data)
|
||||
if response.get("code") != 200:
|
||||
raise Exception(f"API error: {response.get('message', 'Unknown error')}")
|
||||
|
||||
@@ -82,7 +82,12 @@ class ContractSettlementApiHandler(BaseApiHandler):
|
||||
push_id = self._generate_push_id()
|
||||
|
||||
try:
|
||||
response = await api_create_contract_settlement(self.api_client, create_model, push_id)
|
||||
response = await api_create_contract_settlement(
|
||||
self.api_client,
|
||||
create_model,
|
||||
push_id,
|
||||
steps=self._get_request_steps(node),
|
||||
)
|
||||
if self.poll_mode == "sync":
|
||||
created_id = self._extract_created_id_from_response(response)
|
||||
if not created_id:
|
||||
@@ -130,14 +135,31 @@ class ContractSettlementApiHandler(BaseApiHandler):
|
||||
|
||||
node_updated = False
|
||||
error = None
|
||||
steps_payload = self._get_request_steps(node)
|
||||
steps_sent = False
|
||||
|
||||
# 1. 基础信息更新 (ContractSettlementUpdate)
|
||||
base_diff = self._get_schema_diff(ContractSettlementUpdate, data, origin_data, node.node_id)
|
||||
force_steps_update = self._steps_changed(node)
|
||||
base_diff = self._get_schema_diff(
|
||||
ContractSettlementUpdate,
|
||||
data,
|
||||
origin_data,
|
||||
node.node_id,
|
||||
force_full_schema=force_steps_update,
|
||||
)
|
||||
if base_diff:
|
||||
try:
|
||||
update_model = ContractSettlementUpdate.model_validate(data)
|
||||
push_id = self._generate_push_id()
|
||||
await api_update_contract_settlement(self.api_client, update_model, push_id, biz_id)
|
||||
await api_update_contract_settlement(
|
||||
self.api_client,
|
||||
update_model,
|
||||
push_id,
|
||||
biz_id,
|
||||
steps=steps_payload if not steps_sent else [],
|
||||
)
|
||||
self._mark_approval_snapshot_synced(node)
|
||||
steps_sent = steps_sent or bool(steps_payload)
|
||||
node_updated = True
|
||||
except ValidationError as e:
|
||||
error = f"Validation failed: {e}"
|
||||
@@ -151,7 +173,15 @@ class ContractSettlementApiHandler(BaseApiHandler):
|
||||
plan_model = ContractSettlementPlanUpdate.model_validate(data)
|
||||
push_id = self._generate_push_id()
|
||||
# 使用计划更新专用 API
|
||||
await api_update_settlement_plan(self.api_client, plan_model.model_dump(exclude_unset=True), push_id, biz_id)
|
||||
await api_update_settlement_plan(
|
||||
self.api_client,
|
||||
plan_model.model_dump(exclude_unset=True),
|
||||
push_id,
|
||||
biz_id,
|
||||
steps=steps_payload if not steps_sent else [],
|
||||
)
|
||||
self._mark_approval_snapshot_synced(node)
|
||||
steps_sent = steps_sent or bool(steps_payload)
|
||||
node_updated = True
|
||||
except ValidationError as e:
|
||||
error = f"Validation failed: {e}"
|
||||
@@ -255,7 +285,13 @@ async def api_get_contract_settlement_list(client, project_id: str) -> List[Cont
|
||||
return validated_items
|
||||
|
||||
|
||||
async def api_create_contract_settlement(client, data: ContractSettlementCreate, push_id: str) -> Dict[str, Any]:
|
||||
async def api_create_contract_settlement(
|
||||
client,
|
||||
data: ContractSettlementCreate,
|
||||
push_id: str,
|
||||
*,
|
||||
steps: List[Dict[str, Any]] | None = None,
|
||||
) -> Dict[str, Any]:
|
||||
"""
|
||||
创建合同结算 POST /contract_settlement/create
|
||||
|
||||
@@ -271,14 +307,21 @@ async def api_create_contract_settlement(client, data: ContractSettlementCreate,
|
||||
Raises:
|
||||
Exception: API 返回错误
|
||||
"""
|
||||
request_data = {"push_id": push_id, "data": data.model_dump()}
|
||||
request_data = {"push_id": push_id, "data": data.model_dump(), "steps": steps or []}
|
||||
response = await client.request(method="POST", endpoint="/contract_settlement/create", data=request_data)
|
||||
if response.get("code") != 200:
|
||||
raise Exception(f"API error: {response.get('message', 'Unknown error')}")
|
||||
return response
|
||||
|
||||
|
||||
async def api_update_contract_settlement(client, data: ContractSettlementUpdate, push_id: str, biz_id: str) -> None:
|
||||
async def api_update_contract_settlement(
|
||||
client,
|
||||
data: ContractSettlementUpdate,
|
||||
push_id: str,
|
||||
biz_id: str,
|
||||
*,
|
||||
steps: List[Dict[str, Any]] | None = None,
|
||||
) -> None:
|
||||
"""
|
||||
更新合同结算 PUT /contract_settlement/update
|
||||
|
||||
@@ -291,7 +334,7 @@ async def api_update_contract_settlement(client, data: ContractSettlementUpdate,
|
||||
Raises:
|
||||
Exception: API 返回错误
|
||||
"""
|
||||
request_data = {"push_id": push_id, "biz_id": biz_id, "data": data.model_dump(exclude_unset=True)}
|
||||
request_data = {"push_id": push_id, "biz_id": biz_id, "data": data.model_dump(exclude_unset=True), "steps": steps or []}
|
||||
response = await client.request(method="PUT", endpoint="/contract_settlement/update", data=request_data)
|
||||
if response.get("code") != 200:
|
||||
raise Exception(f"API error: {response.get('message', 'Unknown error')}")
|
||||
@@ -305,9 +348,16 @@ async def api_delete_contract_settlement(client, settlement_id: str, push_id: st
|
||||
raise Exception(f"API error: {response.get('message', 'Unknown error')}")
|
||||
|
||||
|
||||
async def api_update_settlement_plan(client, data: Dict[str, Any], push_id: str, biz_id: str) -> None:
|
||||
async def api_update_settlement_plan(
|
||||
client,
|
||||
data: Dict[str, Any],
|
||||
push_id: str,
|
||||
biz_id: str,
|
||||
*,
|
||||
steps: List[Dict[str, Any]] | None = None,
|
||||
) -> None:
|
||||
"""更新合同结算计划 PUT /contract_settlement/plan"""
|
||||
request_data = {"push_id": push_id, "biz_id": biz_id, "data": data}
|
||||
request_data = {"push_id": push_id, "biz_id": biz_id, "data": data, "steps": steps or []}
|
||||
response = await client.request(method="PUT", endpoint="/contract_settlement/plan", data=request_data)
|
||||
if response.get("code") != 200:
|
||||
raise Exception(f"API error: {response.get('message', 'Unknown error')}")
|
||||
|
||||
@@ -76,7 +76,12 @@ class ContractSettlementDetailApiHandler(BaseApiHandler):
|
||||
push_id = self._generate_push_id()
|
||||
|
||||
try:
|
||||
response = await api_create_contract_settlement_detail(self.api_client, create_model, push_id)
|
||||
response = await api_create_contract_settlement_detail(
|
||||
self.api_client,
|
||||
create_model,
|
||||
push_id,
|
||||
steps=self._get_request_steps(node),
|
||||
)
|
||||
if self.poll_mode == "sync":
|
||||
created_id = self._extract_created_id_from_response(response)
|
||||
if not created_id:
|
||||
@@ -118,7 +123,14 @@ class ContractSettlementDetailApiHandler(BaseApiHandler):
|
||||
origin_data = node.get_origin_data() or {}
|
||||
|
||||
# 使用 _get_schema_diff 检查差异并打印日志
|
||||
diff_fields = self._get_schema_diff(ContractSettlementDetailUpdate, data, origin_data, node.node_id)
|
||||
force_steps_update = self._steps_changed(node)
|
||||
diff_fields = self._get_schema_diff(
|
||||
ContractSettlementDetailUpdate,
|
||||
data,
|
||||
origin_data,
|
||||
node.node_id,
|
||||
force_full_schema=force_steps_update,
|
||||
)
|
||||
if not diff_fields:
|
||||
from ...common.types import SyncAction
|
||||
results.append(TaskResult.skipped(node_id=node.node_id, reason="No updatable fields changed"))
|
||||
@@ -131,7 +143,12 @@ class ContractSettlementDetailApiHandler(BaseApiHandler):
|
||||
continue
|
||||
|
||||
# 需要完整的 schema 数据(包括必填字段)
|
||||
update_data = self._filter_update_data(data, origin_data, ContractSettlementDetailUpdate)
|
||||
update_data = self._filter_update_data(
|
||||
data,
|
||||
origin_data,
|
||||
ContractSettlementDetailUpdate,
|
||||
force_full_schema=force_steps_update,
|
||||
)
|
||||
|
||||
try:
|
||||
update_model = ContractSettlementDetailUpdate.model_validate(update_data)
|
||||
@@ -145,6 +162,7 @@ class ContractSettlementDetailApiHandler(BaseApiHandler):
|
||||
|
||||
# 准备批量数据
|
||||
detail_list = [model.model_dump(mode='json', exclude_unset=True) for node, model in group_items]
|
||||
steps = self._get_request_steps(group_items[0][0]) if group_items else []
|
||||
|
||||
# 使用第一个节点的 biz_id(对于批量更新,通常使用 parent_id)
|
||||
biz_id = settlement_id
|
||||
@@ -156,9 +174,11 @@ class ContractSettlementDetailApiHandler(BaseApiHandler):
|
||||
{"detail_list": detail_list},
|
||||
push_id,
|
||||
biz_id,
|
||||
steps=steps,
|
||||
)
|
||||
# 整组成功
|
||||
for node, _ in group_items:
|
||||
self._mark_approval_snapshot_synced(node)
|
||||
results.append(TaskResult.success(node_id=node.node_id, push_id=push_id))
|
||||
except Exception as e:
|
||||
# 整组失败
|
||||
@@ -239,7 +259,13 @@ async def api_get_contract_settlement_detail_list(client, settlement_id: str) ->
|
||||
return validated_items
|
||||
|
||||
|
||||
async def api_create_contract_settlement_detail(client, data: ContractSettlementDetailCreate, push_id: str) -> Dict[str, Any]:
|
||||
async def api_create_contract_settlement_detail(
|
||||
client,
|
||||
data: ContractSettlementDetailCreate,
|
||||
push_id: str,
|
||||
*,
|
||||
steps: List[Dict[str, Any]] | None = None,
|
||||
) -> Dict[str, Any]:
|
||||
"""
|
||||
创建合同结算明细
|
||||
|
||||
@@ -255,14 +281,21 @@ async def api_create_contract_settlement_detail(client, data: ContractSettlement
|
||||
Raises:
|
||||
Exception: API 返回错误
|
||||
"""
|
||||
request_data = {"push_id": push_id, "data": data.model_dump(mode='json')}
|
||||
request_data = {"push_id": push_id, "data": data.model_dump(mode='json'), "steps": steps or []}
|
||||
response = await client.request(method="POST", endpoint="/contract_settlement/detail/create", data=request_data)
|
||||
if response.get("code") != 200:
|
||||
raise Exception(f"API error: {response.get('message', 'Unknown error')}")
|
||||
return response
|
||||
|
||||
|
||||
async def api_update_contract_settlement_detail(client, data: Dict[str, Any], push_id: str, biz_id: str) -> None:
|
||||
async def api_update_contract_settlement_detail(
|
||||
client,
|
||||
data: Dict[str, Any],
|
||||
push_id: str,
|
||||
biz_id: str,
|
||||
*,
|
||||
steps: List[Dict[str, Any]] | None = None,
|
||||
) -> None:
|
||||
"""
|
||||
更新合同结算明细
|
||||
|
||||
@@ -275,7 +308,7 @@ async def api_update_contract_settlement_detail(client, data: Dict[str, Any], pu
|
||||
Raises:
|
||||
Exception: API 返回错误
|
||||
"""
|
||||
request_data = {"push_id": push_id, "biz_id": biz_id, "data": data}
|
||||
request_data = {"push_id": push_id, "biz_id": biz_id, "data": data, "steps": steps or []}
|
||||
response = await client.request(method="PUT", endpoint="/contract_settlement/detail/update", data=request_data)
|
||||
if response.get("code") != 200:
|
||||
raise Exception(f"API error: {response.get('message', 'Unknown error')}")
|
||||
|
||||
@@ -111,10 +111,19 @@ class LarApiHandler(BaseApiHandler):
|
||||
|
||||
origin_data = node.get_origin_data() or {}
|
||||
node_updated = False
|
||||
force_steps_update = self._steps_changed(node)
|
||||
steps_payload = self._get_request_steps(node)
|
||||
steps_sent = False
|
||||
allow_force_steps = True
|
||||
|
||||
for schema, api_func in update_configs:
|
||||
# 获取过滤后的更新数据
|
||||
update_data = self._filter_update_data(node_data, origin_data, schema)
|
||||
update_data = self._filter_update_data(
|
||||
node_data,
|
||||
origin_data,
|
||||
schema,
|
||||
force_full_schema=force_steps_update and allow_force_steps,
|
||||
)
|
||||
if update_data:
|
||||
# 验证并转换为 Pydantic model
|
||||
try:
|
||||
@@ -131,8 +140,17 @@ class LarApiHandler(BaseApiHandler):
|
||||
break
|
||||
|
||||
try:
|
||||
await api_func(self.api_client, update_model, push_id, biz_id)
|
||||
await api_func(
|
||||
self.api_client,
|
||||
update_model,
|
||||
push_id,
|
||||
biz_id,
|
||||
steps=steps_payload if not steps_sent else [],
|
||||
)
|
||||
node_updated = True
|
||||
steps_sent = steps_sent or bool(steps_payload)
|
||||
allow_force_steps = False
|
||||
self._mark_approval_snapshot_synced(node)
|
||||
except Exception as e:
|
||||
results.append(TaskResult.failed(node_id=node.node_id, error=str(e)))
|
||||
break
|
||||
@@ -170,7 +188,14 @@ class LarApiHandler(BaseApiHandler):
|
||||
|
||||
# ========== 静态 API 函数 ==========
|
||||
|
||||
async def api_update_lar_main(client, data: LarMainInfoUpdateSchema, push_id: str, biz_id: str) -> None:
|
||||
async def api_update_lar_main(
|
||||
client,
|
||||
data: LarMainInfoUpdateSchema,
|
||||
push_id: str,
|
||||
biz_id: str,
|
||||
*,
|
||||
steps: List[Dict[str, Any]] | None = None,
|
||||
) -> None:
|
||||
"""
|
||||
PUT /lar/main - 更新主数据
|
||||
|
||||
@@ -180,13 +205,20 @@ async def api_update_lar_main(client, data: LarMainInfoUpdateSchema, push_id: st
|
||||
push_id: 推送ID
|
||||
biz_id: 业务ID
|
||||
"""
|
||||
request_data = {"push_id": push_id, "biz_id": biz_id, "data": data.model_dump(exclude_unset=True)}
|
||||
request_data = {"push_id": push_id, "biz_id": biz_id, "data": data.model_dump(exclude_unset=True), "steps": steps or []}
|
||||
response = await client.request(method="PUT", endpoint="/lar/main", data=request_data)
|
||||
if response.get("code") != 200:
|
||||
raise Exception(f"API error: {response.get('message', 'Unknown error')}")
|
||||
|
||||
|
||||
async def api_update_lar_resettlement(client, data: LarResettlementSchema, push_id: str, biz_id: str) -> None:
|
||||
async def api_update_lar_resettlement(
|
||||
client,
|
||||
data: LarResettlementSchema,
|
||||
push_id: str,
|
||||
biz_id: str,
|
||||
*,
|
||||
steps: List[Dict[str, Any]] | None = None,
|
||||
) -> None:
|
||||
"""
|
||||
PUT /lar/resettlement - 更新搬迁信息
|
||||
|
||||
@@ -196,13 +228,20 @@ async def api_update_lar_resettlement(client, data: LarResettlementSchema, push_
|
||||
push_id: 推送ID
|
||||
biz_id: 业务ID
|
||||
"""
|
||||
request_data = {"push_id": push_id, "biz_id": biz_id, "data": data.model_dump(exclude_unset=True)}
|
||||
request_data = {"push_id": push_id, "biz_id": biz_id, "data": data.model_dump(exclude_unset=True), "steps": steps or []}
|
||||
response = await client.request(method="PUT", endpoint="/lar/resettlement", data=request_data)
|
||||
if response.get("code") != 200:
|
||||
raise Exception(f"API error: {response.get('message', 'Unknown error')}")
|
||||
|
||||
|
||||
async def api_update_lar_investment(client, data: LarInvestmentSchema, push_id: str, biz_id: str) -> None:
|
||||
async def api_update_lar_investment(
|
||||
client,
|
||||
data: LarInvestmentSchema,
|
||||
push_id: str,
|
||||
biz_id: str,
|
||||
*,
|
||||
steps: List[Dict[str, Any]] | None = None,
|
||||
) -> None:
|
||||
"""
|
||||
PUT /lar/investment - 更新投资信息
|
||||
|
||||
@@ -212,7 +251,7 @@ async def api_update_lar_investment(client, data: LarInvestmentSchema, push_id:
|
||||
push_id: 推送ID
|
||||
biz_id: 业务ID
|
||||
"""
|
||||
request_data = {"push_id": push_id, "biz_id": biz_id, "data": data.model_dump(exclude_unset=True)}
|
||||
request_data = {"push_id": push_id, "biz_id": biz_id, "data": data.model_dump(exclude_unset=True), "steps": steps or []}
|
||||
response = await client.request(method="PUT", endpoint="/lar/investment", data=request_data)
|
||||
if response.get("code") != 200:
|
||||
raise Exception(f"API error: {response.get('message', 'Unknown error')}")
|
||||
|
||||
@@ -67,7 +67,12 @@ class LarChangeApiHandler(BaseApiHandler):
|
||||
push_id = self._generate_push_id()
|
||||
|
||||
try:
|
||||
response = await api_create_lar_change(self.api_client, create_model, push_id)
|
||||
response = await api_create_lar_change(
|
||||
self.api_client,
|
||||
create_model,
|
||||
push_id,
|
||||
steps=self._get_request_steps(node),
|
||||
)
|
||||
if self.poll_mode == "sync":
|
||||
created_id = self._extract_created_id_from_response(response)
|
||||
if not created_id:
|
||||
@@ -98,7 +103,13 @@ class LarChangeApiHandler(BaseApiHandler):
|
||||
results.append(TaskResult.failed(node_id=node.node_id, error=f"Cannot update: {error_msg}"))
|
||||
continue
|
||||
origin_data = node.get_origin_data() or {}
|
||||
update_data = self._filter_update_data(node_data, origin_data, LarChangeUpdateSchema)
|
||||
force_steps_update = self._steps_changed(node)
|
||||
update_data = self._filter_update_data(
|
||||
node_data,
|
||||
origin_data,
|
||||
LarChangeUpdateSchema,
|
||||
force_full_schema=force_steps_update,
|
||||
)
|
||||
if not update_data:
|
||||
from ...common.types import SyncAction
|
||||
results.append(TaskResult.skipped(node_id=node.node_id, reason="No updatable fields changed"))
|
||||
@@ -118,7 +129,14 @@ class LarChangeApiHandler(BaseApiHandler):
|
||||
continue
|
||||
|
||||
try:
|
||||
await api_update_lar_change(self.api_client, update_model, push_id, biz_id)
|
||||
await api_update_lar_change(
|
||||
self.api_client,
|
||||
update_model,
|
||||
push_id,
|
||||
biz_id,
|
||||
steps=self._get_request_steps(node),
|
||||
)
|
||||
self._mark_approval_snapshot_synced(node)
|
||||
results.append(TaskResult.success(node_id=node.node_id))
|
||||
except Exception as e:
|
||||
results.append(TaskResult.failed(node_id=node.node_id, error=str(e)))
|
||||
@@ -147,7 +165,13 @@ class LarChangeApiHandler(BaseApiHandler):
|
||||
|
||||
# ========== 静态 API 函数 ==========
|
||||
|
||||
async def api_create_lar_change(client, data: LarChangeCreateSchema, push_id: str) -> Dict[str, Any]:
|
||||
async def api_create_lar_change(
|
||||
client,
|
||||
data: LarChangeCreateSchema,
|
||||
push_id: str,
|
||||
*,
|
||||
steps: List[Dict[str, Any]] | None = None,
|
||||
) -> Dict[str, Any]:
|
||||
"""
|
||||
POST /lar/change - 创建移民变更
|
||||
|
||||
@@ -157,14 +181,21 @@ async def api_create_lar_change(client, data: LarChangeCreateSchema, push_id: st
|
||||
push_id: 推送ID
|
||||
biz_id: 业务ID
|
||||
"""
|
||||
request_data = {"push_id": push_id, "data": data.model_dump()}
|
||||
request_data = {"push_id": push_id, "data": data.model_dump(), "steps": steps or []}
|
||||
response = await client.request(method="POST", endpoint="/lar/change", data=request_data)
|
||||
if response.get("code") != 200:
|
||||
raise Exception(f"API error: {response.get('message', 'Unknown error')}")
|
||||
return response
|
||||
|
||||
|
||||
async def api_update_lar_change(client, data: LarChangeUpdateSchema, push_id: str, biz_id: str) -> None:
|
||||
async def api_update_lar_change(
|
||||
client,
|
||||
data: LarChangeUpdateSchema,
|
||||
push_id: str,
|
||||
biz_id: str,
|
||||
*,
|
||||
steps: List[Dict[str, Any]] | None = None,
|
||||
) -> None:
|
||||
"""
|
||||
PUT /lar/change - 更新移民变更
|
||||
|
||||
@@ -174,7 +205,7 @@ async def api_update_lar_change(client, data: LarChangeUpdateSchema, push_id: st
|
||||
push_id: 推送ID
|
||||
biz_id: 业务ID
|
||||
"""
|
||||
request_data = {"push_id": push_id, "biz_id": biz_id, "data": data.model_dump(exclude_unset=True)}
|
||||
request_data = {"push_id": push_id, "biz_id": biz_id, "data": data.model_dump(exclude_unset=True), "steps": steps or []}
|
||||
response = await client.request(method="PUT", endpoint="/lar/change", data=request_data)
|
||||
if response.get("code") != 200:
|
||||
raise Exception(f"API error: {response.get('message', 'Unknown error')}")
|
||||
|
||||
@@ -101,14 +101,31 @@ class MaterialApiHandler(BaseApiHandler):
|
||||
|
||||
node_updated = False
|
||||
error = None
|
||||
steps_payload = self._get_request_steps(node)
|
||||
steps_sent = False
|
||||
|
||||
# 1. 基础信息更新 (MaterialUpdate)
|
||||
base_diff = self._get_schema_diff(MaterialUpdate, data, origin_data, node.node_id)
|
||||
force_steps_update = self._steps_changed(node)
|
||||
base_diff = self._get_schema_diff(
|
||||
MaterialUpdate,
|
||||
data,
|
||||
origin_data,
|
||||
node.node_id,
|
||||
force_full_schema=force_steps_update,
|
||||
)
|
||||
if base_diff:
|
||||
try:
|
||||
update_model = MaterialUpdate.model_validate(data)
|
||||
push_id = self._generate_push_id()
|
||||
await api_update_material(self.api_client, update_model, push_id, biz_id)
|
||||
await api_update_material(
|
||||
self.api_client,
|
||||
update_model,
|
||||
push_id,
|
||||
biz_id,
|
||||
steps=steps_payload if not steps_sent else [],
|
||||
)
|
||||
self._mark_approval_snapshot_synced(node)
|
||||
steps_sent = steps_sent or bool(steps_payload)
|
||||
node_updated = True
|
||||
except ValidationError as e:
|
||||
error = f"{ERROR_VALIDATION_FAILED}: {e}"
|
||||
@@ -124,8 +141,11 @@ class MaterialApiHandler(BaseApiHandler):
|
||||
self.api_client,
|
||||
plan_model.model_dump(exclude_unset=True),
|
||||
push_id,
|
||||
biz_id
|
||||
biz_id,
|
||||
steps=steps_payload if not steps_sent else [],
|
||||
)
|
||||
self._mark_approval_snapshot_synced(node)
|
||||
steps_sent = steps_sent or bool(steps_payload)
|
||||
node_updated = True
|
||||
except ValidationError as e:
|
||||
error = f"{ERROR_VALIDATION_FAILED}: {e}"
|
||||
@@ -182,7 +202,12 @@ class MaterialApiHandler(BaseApiHandler):
|
||||
error=f"{ERROR_VALIDATION_FAILED}: {e}"
|
||||
)
|
||||
|
||||
response = await api_create_material(self.api_client, create_model, push_id)
|
||||
response = await api_create_material(
|
||||
self.api_client,
|
||||
create_model,
|
||||
push_id,
|
||||
steps=self._get_request_steps(node),
|
||||
)
|
||||
if self.poll_mode == "sync":
|
||||
created_id = self._extract_created_id_from_response(response)
|
||||
if not created_id:
|
||||
@@ -330,26 +355,40 @@ async def api_get_material_list(client, project_id: str) -> List[MaterialRespons
|
||||
return validated_items
|
||||
|
||||
|
||||
async def api_create_material(client, data: MaterialCreate, push_id: str) -> Dict[str, Any]:
|
||||
async def api_create_material(client, data: MaterialCreate, push_id: str, *, steps: List[Dict[str, Any]] | None = None) -> Dict[str, Any]:
|
||||
"""创建物资 POST /material/create"""
|
||||
request_data = {"push_id": push_id, "data": data.model_dump()}
|
||||
request_data = {"push_id": push_id, "data": data.model_dump(), "steps": steps or []}
|
||||
response = await client.request(method="POST", endpoint="/material/create", data=request_data)
|
||||
if response.get("code") != 200:
|
||||
raise Exception(f"API error: {response.get('message', 'Unknown error')}")
|
||||
return response
|
||||
|
||||
|
||||
async def api_update_material(client, data: MaterialUpdate, push_id: str, biz_id: str) -> None:
|
||||
async def api_update_material(
|
||||
client,
|
||||
data: MaterialUpdate,
|
||||
push_id: str,
|
||||
biz_id: str,
|
||||
*,
|
||||
steps: List[Dict[str, Any]] | None = None,
|
||||
) -> None:
|
||||
"""更新物资 PUT /material/update"""
|
||||
request_data = {"push_id": push_id, "biz_id": biz_id, "data": data.model_dump(exclude_unset=True)}
|
||||
request_data = {"push_id": push_id, "biz_id": biz_id, "data": data.model_dump(exclude_unset=True), "steps": steps or []}
|
||||
response = await client.request(method="PUT", endpoint="/material/update", data=request_data)
|
||||
if response.get("code") != 200:
|
||||
raise Exception(f"API error: {response.get('message', 'Unknown error')}")
|
||||
|
||||
|
||||
async def api_update_material_plan(client, data: Dict[str, Any], push_id: str, biz_id: str) -> None:
|
||||
async def api_update_material_plan(
|
||||
client,
|
||||
data: Dict[str, Any],
|
||||
push_id: str,
|
||||
biz_id: str,
|
||||
*,
|
||||
steps: List[Dict[str, Any]] | None = None,
|
||||
) -> None:
|
||||
"""更新物资计划 PUT /material/plan"""
|
||||
request_data = {"push_id": push_id, "biz_id": biz_id, "data": data}
|
||||
request_data = {"push_id": push_id, "biz_id": biz_id, "data": data, "steps": steps or []}
|
||||
response = await client.request(method="PUT", endpoint="/material/plan", data=request_data)
|
||||
if response.get("code") != 200:
|
||||
raise Exception(f"API error: {response.get('message', 'Unknown error')}")
|
||||
|
||||
@@ -102,6 +102,7 @@ class MaterialDetailApiHandler(BaseApiHandler):
|
||||
self.api_client,
|
||||
create_model,
|
||||
push_id,
|
||||
steps=self._get_request_steps(node),
|
||||
)
|
||||
if self.poll_mode == "sync":
|
||||
created_id = self._extract_created_id_from_response(response)
|
||||
@@ -144,7 +145,14 @@ class MaterialDetailApiHandler(BaseApiHandler):
|
||||
origin_data = node.get_origin_data() or {}
|
||||
|
||||
# 使用 _get_schema_diff 检查差异并打印日志
|
||||
diff_fields = self._get_schema_diff(MaterialDetailUpdate, data, origin_data, node.node_id)
|
||||
force_steps_update = self._steps_changed(node)
|
||||
diff_fields = self._get_schema_diff(
|
||||
MaterialDetailUpdate,
|
||||
data,
|
||||
origin_data,
|
||||
node.node_id,
|
||||
force_full_schema=force_steps_update,
|
||||
)
|
||||
if not diff_fields:
|
||||
from ...common.types import SyncAction
|
||||
results.append(TaskResult.skipped(node_id=node.node_id, reason="No updatable fields changed"))
|
||||
@@ -157,7 +165,12 @@ class MaterialDetailApiHandler(BaseApiHandler):
|
||||
continue
|
||||
|
||||
# 需要完整的 schema 数据(包括必填字段)
|
||||
update_data = self._filter_update_data(data, origin_data, MaterialDetailUpdate)
|
||||
update_data = self._filter_update_data(
|
||||
data,
|
||||
origin_data,
|
||||
MaterialDetailUpdate,
|
||||
force_full_schema=force_steps_update,
|
||||
)
|
||||
|
||||
# 验证并转换为 Pydantic model
|
||||
try:
|
||||
@@ -174,6 +187,7 @@ class MaterialDetailApiHandler(BaseApiHandler):
|
||||
|
||||
# 准备批量数据
|
||||
detail_list = [model.model_dump(mode='json', exclude_unset=True) for node, model in group_items]
|
||||
steps = self._get_request_steps(group_items[0][0]) if group_items else []
|
||||
|
||||
# 使用 parent_id(material_id)作为 biz_id
|
||||
biz_id = material_id
|
||||
@@ -184,10 +198,12 @@ class MaterialDetailApiHandler(BaseApiHandler):
|
||||
self.api_client,
|
||||
{"detail_list": detail_list},
|
||||
push_id,
|
||||
biz_id
|
||||
biz_id,
|
||||
steps=steps,
|
||||
)
|
||||
# 整组成功
|
||||
for node, _ in group_items:
|
||||
self._mark_approval_snapshot_synced(node)
|
||||
results.append(TaskResult.in_progress(node_id=node.node_id, task_id=push_id))
|
||||
except Exception as e:
|
||||
# 整组失败
|
||||
@@ -271,7 +287,13 @@ async def api_get_material_detail_list(client, material_id: str) -> List[Materia
|
||||
return validated_items
|
||||
|
||||
|
||||
async def api_create_material_detail(client, data: MaterialDetailCreate, push_id: str) -> Dict[str, Any]:
|
||||
async def api_create_material_detail(
|
||||
client,
|
||||
data: MaterialDetailCreate,
|
||||
push_id: str,
|
||||
*,
|
||||
steps: List[Dict[str, Any]] | None = None,
|
||||
) -> Dict[str, Any]:
|
||||
"""
|
||||
创建物资明细 POST /material_detail/create
|
||||
|
||||
@@ -281,7 +303,7 @@ async def api_create_material_detail(client, data: MaterialDetailCreate, push_id
|
||||
push_id: 推送ID
|
||||
biz_id: 业务ID
|
||||
"""
|
||||
request_data = {"push_id": push_id, "data": data.model_dump(mode='json')}
|
||||
request_data = {"push_id": push_id, "data": data.model_dump(mode='json'), "steps": steps or []}
|
||||
response = await client.request(
|
||||
method="POST",
|
||||
endpoint="/material/detail/create",
|
||||
@@ -292,7 +314,14 @@ async def api_create_material_detail(client, data: MaterialDetailCreate, push_id
|
||||
return response
|
||||
|
||||
|
||||
async def api_update_material_detail(client, data: Dict[str, Any], push_id: str, biz_id: str):
|
||||
async def api_update_material_detail(
|
||||
client,
|
||||
data: Dict[str, Any],
|
||||
push_id: str,
|
||||
biz_id: str,
|
||||
*,
|
||||
steps: List[Dict[str, Any]] | None = None,
|
||||
):
|
||||
"""
|
||||
更新物资明细 PUT /material_detail/update
|
||||
|
||||
@@ -305,7 +334,8 @@ async def api_update_material_detail(client, data: Dict[str, Any], push_id: str,
|
||||
request_data = {
|
||||
"push_id": push_id,
|
||||
"biz_id": biz_id,
|
||||
"data": data
|
||||
"data": data,
|
||||
"steps": steps or [],
|
||||
}
|
||||
response = await client.request(
|
||||
method="PUT",
|
||||
|
||||
@@ -63,7 +63,12 @@ class PersonnelApiHandler(BaseApiHandler):
|
||||
try:
|
||||
request_data = {"project_id": project_id, **data}
|
||||
PowerCreate.model_validate(request_data)
|
||||
response = await api_create_personnel(self.api_client, request_data, push_id)
|
||||
response = await api_create_personnel(
|
||||
self.api_client,
|
||||
request_data,
|
||||
push_id,
|
||||
steps=self._get_request_steps(node),
|
||||
)
|
||||
if self.poll_mode == "sync":
|
||||
created_id = self._extract_created_id_from_response(response)
|
||||
if not created_id:
|
||||
@@ -111,14 +116,31 @@ class PersonnelApiHandler(BaseApiHandler):
|
||||
|
||||
node_updated = False
|
||||
error = None
|
||||
steps_payload = self._get_request_steps(node)
|
||||
steps_sent = False
|
||||
|
||||
# 1. 基础信息更新 (PowerUpdate)
|
||||
base_diff = self._get_schema_diff(PowerUpdate, data, origin_data, node.node_id)
|
||||
force_steps_update = self._steps_changed(node)
|
||||
base_diff = self._get_schema_diff(
|
||||
PowerUpdate,
|
||||
data,
|
||||
origin_data,
|
||||
node.node_id,
|
||||
force_full_schema=force_steps_update,
|
||||
)
|
||||
if base_diff:
|
||||
try:
|
||||
update_model = PowerUpdate.model_validate(data)
|
||||
push_id = self._generate_push_id()
|
||||
await api_update_personnel(self.api_client, update_model.model_dump(), push_id, biz_id)
|
||||
await api_update_personnel(
|
||||
self.api_client,
|
||||
update_model.model_dump(),
|
||||
push_id,
|
||||
biz_id,
|
||||
steps=steps_payload if not steps_sent else [],
|
||||
)
|
||||
self._mark_approval_snapshot_synced(node)
|
||||
steps_sent = steps_sent or bool(steps_payload)
|
||||
node_updated = True
|
||||
except ValidationError as e:
|
||||
error = f"Validation failed: {e}"
|
||||
@@ -144,7 +166,10 @@ class PersonnelApiHandler(BaseApiHandler):
|
||||
plan_model.model_dump(),
|
||||
push_id,
|
||||
biz_id,
|
||||
steps=steps_payload if not steps_sent else [],
|
||||
)
|
||||
self._mark_approval_snapshot_synced(node)
|
||||
steps_sent = steps_sent or bool(steps_payload)
|
||||
node_updated = True
|
||||
except ValidationError as e:
|
||||
error = f"Validation failed: {e}"
|
||||
@@ -207,18 +232,31 @@ async def api_get_personnel(client, personnel_id: str) -> Dict[str, Any]:
|
||||
return response.get("data", {})
|
||||
|
||||
|
||||
async def api_create_personnel(client, data: Dict[str, Any], push_id: str) -> Dict[str, Any]:
|
||||
async def api_create_personnel(
|
||||
client,
|
||||
data: Dict[str, Any],
|
||||
push_id: str,
|
||||
*,
|
||||
steps: List[Dict[str, Any]] | None = None,
|
||||
) -> Dict[str, Any]:
|
||||
"""创建力能 POST /personnel/create"""
|
||||
request_data = {"push_id": push_id, "data": data}
|
||||
request_data = {"push_id": push_id, "data": data, "steps": steps or []}
|
||||
response = await client.request(method="POST", endpoint="/personnel/create", data=request_data)
|
||||
if response.get("code") != 200:
|
||||
raise Exception(f"API error: {response.get('message', 'Unknown error')}")
|
||||
return response
|
||||
|
||||
|
||||
async def api_update_personnel(client, data: Dict[str, Any], push_id: str, biz_id: str) -> None:
|
||||
async def api_update_personnel(
|
||||
client,
|
||||
data: Dict[str, Any],
|
||||
push_id: str,
|
||||
biz_id: str,
|
||||
*,
|
||||
steps: List[Dict[str, Any]] | None = None,
|
||||
) -> None:
|
||||
"""更新力能 PUT /personnel/update"""
|
||||
request_data = {"push_id": push_id, "biz_id": biz_id, "data": data}
|
||||
request_data = {"push_id": push_id, "biz_id": biz_id, "data": data, "steps": steps or []}
|
||||
response = await client.request(method="PUT", endpoint="/personnel/update", data=request_data)
|
||||
if response.get("code") != 200:
|
||||
raise Exception(f"API error: {response.get('message', 'Unknown error')}")
|
||||
@@ -252,9 +290,16 @@ async def api_delete_personnel(client, personnel_id: str, push_id: str) -> None:
|
||||
raise Exception(f"API error: {response.get('message', 'Unknown error')}")
|
||||
|
||||
|
||||
async def api_update_personnel_plan(client, data: Dict[str, Any], push_id: str, biz_id: str) -> None:
|
||||
async def api_update_personnel_plan(
|
||||
client,
|
||||
data: Dict[str, Any],
|
||||
push_id: str,
|
||||
biz_id: str,
|
||||
*,
|
||||
steps: List[Dict[str, Any]] | None = None,
|
||||
) -> None:
|
||||
"""更新力能计划 PUT /personnel/plan"""
|
||||
request_data = {"push_id": push_id, "biz_id": biz_id, "data": data}
|
||||
request_data = {"push_id": push_id, "biz_id": biz_id, "data": data, "steps": steps or []}
|
||||
response = await client.request(method="PUT", endpoint="/personnel/plan", data=request_data)
|
||||
if response.get("code") != 200:
|
||||
raise Exception(f"API error: {response.get('message', 'Unknown error')}")
|
||||
|
||||
@@ -65,7 +65,12 @@ class PersonnelDetailApiHandler(BaseApiHandler):
|
||||
try:
|
||||
request_data = {"personnel_id": personnel_id, **data}
|
||||
PowerDetailCreate.model_validate(request_data)
|
||||
response = await api_create_personnel_detail(self.api_client, request_data, push_id)
|
||||
response = await api_create_personnel_detail(
|
||||
self.api_client,
|
||||
request_data,
|
||||
push_id,
|
||||
steps=self._get_request_steps(node),
|
||||
)
|
||||
if self.poll_mode == "sync":
|
||||
created_id = self._extract_created_id_from_response(response)
|
||||
if not created_id:
|
||||
@@ -107,7 +112,14 @@ class PersonnelDetailApiHandler(BaseApiHandler):
|
||||
origin_data = node.get_origin_data() or {}
|
||||
|
||||
# 使用 _get_schema_diff 检查差异并打印日志
|
||||
diff_fields = self._get_schema_diff(PowerDetailUpdate, data, origin_data, node.node_id)
|
||||
force_steps_update = self._steps_changed(node)
|
||||
diff_fields = self._get_schema_diff(
|
||||
PowerDetailUpdate,
|
||||
data,
|
||||
origin_data,
|
||||
node.node_id,
|
||||
force_full_schema=force_steps_update,
|
||||
)
|
||||
if not diff_fields:
|
||||
from ...common.types import SyncAction
|
||||
results.append(TaskResult.skipped(node_id=node.node_id, reason="No updatable fields changed"))
|
||||
@@ -120,7 +132,12 @@ class PersonnelDetailApiHandler(BaseApiHandler):
|
||||
continue
|
||||
|
||||
# 需要完整的 schema 数据(包括必填字段)
|
||||
update_data = self._filter_update_data(data, origin_data, PowerDetailUpdate)
|
||||
update_data = self._filter_update_data(
|
||||
data,
|
||||
origin_data,
|
||||
PowerDetailUpdate,
|
||||
force_full_schema=force_steps_update,
|
||||
)
|
||||
|
||||
# 验证并转换为 Pydantic model
|
||||
try:
|
||||
@@ -135,6 +152,7 @@ class PersonnelDetailApiHandler(BaseApiHandler):
|
||||
|
||||
# 准备批量数据
|
||||
detail_list = [model.model_dump(exclude_unset=True) for node, model in group_items]
|
||||
steps = self._get_request_steps(group_items[0][0]) if group_items else []
|
||||
|
||||
# 使用 parent_id(personnel_id)作为 biz_id
|
||||
biz_id = personnel_id
|
||||
@@ -146,9 +164,11 @@ class PersonnelDetailApiHandler(BaseApiHandler):
|
||||
{"detail_list": detail_list},
|
||||
push_id,
|
||||
biz_id,
|
||||
steps=steps,
|
||||
)
|
||||
# 整组成功
|
||||
for node, _ in group_items:
|
||||
self._mark_approval_snapshot_synced(node)
|
||||
results.append(TaskResult.success(node_id=node.node_id, push_id=push_id))
|
||||
except Exception as e:
|
||||
# 整组失败
|
||||
@@ -202,16 +222,29 @@ async def api_get_personnel_detail_list(client, personnel_id: str) -> List[Dict[
|
||||
return response.get("data", [])
|
||||
|
||||
|
||||
async def api_create_personnel_detail(client, data: Dict[str, Any], push_id: str) -> Dict[str, Any]:
|
||||
request_data = {"push_id": push_id, "data": data}
|
||||
async def api_create_personnel_detail(
|
||||
client,
|
||||
data: Dict[str, Any],
|
||||
push_id: str,
|
||||
*,
|
||||
steps: List[Dict[str, Any]] | None = None,
|
||||
) -> Dict[str, Any]:
|
||||
request_data = {"push_id": push_id, "data": data, "steps": steps or []}
|
||||
response = await client.request(method="POST", endpoint="/personnel/detail/create", data=request_data)
|
||||
if response.get("code") != 200:
|
||||
raise Exception(f"API error: {response.get('message', 'Unknown error')}")
|
||||
return response
|
||||
|
||||
|
||||
async def api_update_personnel_detail(client, data: Dict[str, Any], push_id: str, biz_id: str) -> None:
|
||||
request_data = {"push_id": push_id, "biz_id": biz_id, "data": data}
|
||||
async def api_update_personnel_detail(
|
||||
client,
|
||||
data: Dict[str, Any],
|
||||
push_id: str,
|
||||
biz_id: str,
|
||||
*,
|
||||
steps: List[Dict[str, Any]] | None = None,
|
||||
) -> None:
|
||||
request_data = {"push_id": push_id, "biz_id": biz_id, "data": data, "steps": steps or []}
|
||||
response = await client.request(method="PUT", endpoint="/personnel/detail/update", data=request_data)
|
||||
if response.get("code") != 200:
|
||||
raise Exception(f"API error: {response.get('message', 'Unknown error')}")
|
||||
|
||||
@@ -102,7 +102,13 @@ class PreparationApiHandler(BaseApiHandler):
|
||||
continue
|
||||
|
||||
origin_data = node.get_origin_data() or {}
|
||||
update_data = self._filter_update_data(node_data, origin_data, PostPreparation)
|
||||
force_steps_update = self._steps_changed(node)
|
||||
update_data = self._filter_update_data(
|
||||
node_data,
|
||||
origin_data,
|
||||
PostPreparation,
|
||||
force_full_schema=force_steps_update,
|
||||
)
|
||||
if not update_data:
|
||||
reason = f"No physical diff found for preparation {node.data_id} despite strategy update request (Normalization Discrepancy)."
|
||||
print(f" [WARNING] [preparation] {reason}")
|
||||
@@ -123,7 +129,14 @@ class PreparationApiHandler(BaseApiHandler):
|
||||
continue
|
||||
|
||||
try:
|
||||
await api_update_preparation(self.api_client, update_model, push_id, biz_id)
|
||||
await api_update_preparation(
|
||||
self.api_client,
|
||||
update_model,
|
||||
push_id,
|
||||
biz_id,
|
||||
steps=self._get_request_steps(node),
|
||||
)
|
||||
self._mark_approval_snapshot_synced(node)
|
||||
results.append(TaskResult.success(node_id=node.node_id))
|
||||
except Exception as e:
|
||||
results.append(TaskResult.failed(node_id=node.node_id, error=str(e)))
|
||||
@@ -143,11 +156,18 @@ class PreparationApiHandler(BaseApiHandler):
|
||||
|
||||
# ========== 静态 API 函数 ==========
|
||||
|
||||
async def api_update_preparation(client, data: PostPreparation, push_id: str, biz_id: str) -> None:
|
||||
async def api_update_preparation(
|
||||
client,
|
||||
data: PostPreparation,
|
||||
push_id: str,
|
||||
biz_id: str,
|
||||
*,
|
||||
steps: List[Dict[str, Any]] | None = None,
|
||||
) -> None:
|
||||
"""
|
||||
PUT /preparation_nodes - 更新里程碑数据
|
||||
"""
|
||||
request_data = {"push_id": push_id, "biz_id": biz_id, "data": data.model_dump(exclude_unset=True)}
|
||||
request_data = {"push_id": push_id, "biz_id": biz_id, "data": data.model_dump(exclude_unset=True), "steps": steps or []}
|
||||
response = await client.request(method="PUT", endpoint="/preparation_nodes", data=request_data)
|
||||
if response.get("code") != 200:
|
||||
raise Exception(f"API error: {response.get('message', 'Unknown error')}")
|
||||
|
||||
@@ -98,7 +98,13 @@ class ProductionApiHandler(BaseApiHandler):
|
||||
origin_data = node.get_origin_data() or {}
|
||||
|
||||
# 获取过滤后的更新数据
|
||||
update_data = self._filter_update_data(node_data, origin_data, PostProduction)
|
||||
force_steps_update = self._steps_changed(node)
|
||||
update_data = self._filter_update_data(
|
||||
node_data,
|
||||
origin_data,
|
||||
PostProduction,
|
||||
force_full_schema=force_steps_update,
|
||||
)
|
||||
|
||||
if not update_data:
|
||||
reason = f"No physical diff found for production {node.data_id} despite strategy update request (Normalization Discrepancy)."
|
||||
@@ -121,7 +127,14 @@ class ProductionApiHandler(BaseApiHandler):
|
||||
continue
|
||||
|
||||
try:
|
||||
await api_update_production(self.api_client, update_model, push_id, biz_id)
|
||||
await api_update_production(
|
||||
self.api_client,
|
||||
update_model,
|
||||
push_id,
|
||||
biz_id,
|
||||
steps=self._get_request_steps(node),
|
||||
)
|
||||
self._mark_approval_snapshot_synced(node)
|
||||
results.append(TaskResult.success(node_id=node.node_id))
|
||||
except Exception as e:
|
||||
results.append(TaskResult.failed(node_id=node.node_id, error=str(e)))
|
||||
@@ -150,7 +163,14 @@ class ProductionApiHandler(BaseApiHandler):
|
||||
|
||||
# ========== 静态 API 函数 ==========
|
||||
|
||||
async def api_update_production(client, data: PostProduction, push_id: str, biz_id: str) -> None:
|
||||
async def api_update_production(
|
||||
client,
|
||||
data: PostProduction,
|
||||
push_id: str,
|
||||
biz_id: str,
|
||||
*,
|
||||
steps: List[Dict[str, Any]] | None = None,
|
||||
) -> None:
|
||||
"""
|
||||
PUT /production - 更新投产节点数据
|
||||
|
||||
@@ -160,7 +180,7 @@ async def api_update_production(client, data: PostProduction, push_id: str, biz_
|
||||
push_id: 推送ID
|
||||
biz_id: 业务ID
|
||||
"""
|
||||
request_data = {"push_id": push_id, "biz_id": biz_id, "data": data.model_dump(exclude_unset=True)}
|
||||
request_data = {"push_id": push_id, "biz_id": biz_id, "data": data.model_dump(exclude_unset=True), "steps": steps or []}
|
||||
response = await client.request(method="PUT", endpoint="/production_nodes", data=request_data)
|
||||
if response.get("code") != 200:
|
||||
raise Exception(f"API error: {response.get('message', 'Unknown error')}")
|
||||
|
||||
@@ -241,22 +241,41 @@ class ProjectApiHandler(BaseApiHandler):
|
||||
|
||||
node_updated = False
|
||||
error = None
|
||||
force_steps_update = self._steps_changed(node)
|
||||
steps_payload = self._get_request_steps(node)
|
||||
steps_sent = False
|
||||
allow_force_steps = True
|
||||
|
||||
# 遍历所有更新 schema,检查差异并更新
|
||||
for schema, api_func in update_configs:
|
||||
update_data = self._get_schema_diff(schema, data, original_data, node.node_id)
|
||||
update_data = self._get_schema_diff(
|
||||
schema,
|
||||
data,
|
||||
original_data,
|
||||
node.node_id,
|
||||
force_full_schema=force_steps_update and allow_force_steps,
|
||||
)
|
||||
if not update_data:
|
||||
continue
|
||||
|
||||
# 执行更新(差异已由 _get_schema_diff 打印)
|
||||
try:
|
||||
full_update_data = self._filter_update_data(data, original_data, schema)
|
||||
full_update_data = self._filter_update_data(
|
||||
data,
|
||||
original_data,
|
||||
schema,
|
||||
force_full_schema=force_steps_update and allow_force_steps,
|
||||
)
|
||||
await self._submit_update_and_wait(
|
||||
api_func=api_func,
|
||||
data=full_update_data,
|
||||
biz_id=biz_id,
|
||||
steps=steps_payload if not steps_sent else [],
|
||||
)
|
||||
node_updated = True
|
||||
steps_sent = steps_sent or bool(steps_payload)
|
||||
allow_force_steps = False
|
||||
self._mark_approval_snapshot_synced(node)
|
||||
except Exception as e:
|
||||
error = str(e)
|
||||
break
|
||||
@@ -285,9 +304,9 @@ class ProjectApiHandler(BaseApiHandler):
|
||||
"""轮询异步任务状态"""
|
||||
return await super().poll_tasks(task_ids)
|
||||
|
||||
async def _submit_update_and_wait(self, *, api_func, data: Dict[str, Any], biz_id: str) -> None:
|
||||
async def _submit_update_and_wait(self, *, api_func, data: Dict[str, Any], biz_id: str, steps: List[Dict[str, Any]] | None = None) -> None:
|
||||
push_id = self._generate_push_id()
|
||||
await api_func(self.api_client, data, push_id, biz_id)
|
||||
await api_func(self.api_client, data, push_id, biz_id, steps=steps or [])
|
||||
|
||||
max_attempts = 20
|
||||
poll_interval = 0.2
|
||||
@@ -400,46 +419,46 @@ async def api_get_project_all_info(client, project_id: str) -> Dict[str, Any]:
|
||||
return validated.model_dump()
|
||||
|
||||
|
||||
async def api_update_project_base_info(client, data: Dict[str, Any], push_id: str, biz_id: str) -> None:
|
||||
async def api_update_project_base_info(client, data: Dict[str, Any], push_id: str, biz_id: str, *, steps: List[Dict[str, Any]] | None = None) -> None:
|
||||
"""PUT /project - 更新项目基本信息"""
|
||||
ProjectBaseInfoUpdate.model_validate(data)
|
||||
request_data = {"push_id": push_id, "biz_id": biz_id, "data": data}
|
||||
request_data = {"push_id": push_id, "biz_id": biz_id, "data": data, "steps": steps or []}
|
||||
response = await client.request(method="PUT", endpoint="/project", data=request_data)
|
||||
if response.get("code") != 200:
|
||||
raise Exception(f"API error: {response.get('message', 'Unknown error')}")
|
||||
|
||||
|
||||
async def api_update_project_key_constraints(client, data: Dict[str, Any], push_id: str, biz_id: str) -> None:
|
||||
async def api_update_project_key_constraints(client, data: Dict[str, Any], push_id: str, biz_id: str, *, steps: List[Dict[str, Any]] | None = None) -> None:
|
||||
"""PUT /project/key_constraints - 更新关键节点"""
|
||||
ProjectKeyConstraints.model_validate(data)
|
||||
request_data = {"push_id": push_id, "biz_id": biz_id, "data": data}
|
||||
request_data = {"push_id": push_id, "biz_id": biz_id, "data": data, "steps": steps or []}
|
||||
response = await client.request(method="PUT", endpoint="/project/key_constraints", data=request_data)
|
||||
if response.get("code") != 200:
|
||||
raise Exception(f"API error: {response.get('message', 'Unknown error')}")
|
||||
|
||||
|
||||
async def api_update_project_complete_investment(client, data: Dict[str, Any], push_id: str, biz_id: str) -> None:
|
||||
async def api_update_project_complete_investment(client, data: Dict[str, Any], push_id: str, biz_id: str, *, steps: List[Dict[str, Any]] | None = None) -> None:
|
||||
"""PUT /project/complete_investment - 更新完成投资"""
|
||||
ProjectCompleteInvestment.model_validate(data)
|
||||
request_data = {"push_id": push_id, "biz_id": biz_id, "data": data}
|
||||
request_data = {"push_id": push_id, "biz_id": biz_id, "data": data, "steps": steps or []}
|
||||
response = await client.request(method="PUT", endpoint="/project/complete_investment", data=request_data)
|
||||
if response.get("code") != 200:
|
||||
raise Exception(f"API error: {response.get('message', 'Unknown error')}")
|
||||
|
||||
|
||||
async def api_update_project_investment_decision(client, data: Dict[str, Any], push_id: str, biz_id: str) -> None:
|
||||
async def api_update_project_investment_decision(client, data: Dict[str, Any], push_id: str, biz_id: str, *, steps: List[Dict[str, Any]] | None = None) -> None:
|
||||
"""PUT /project/investment_decision - 更新投资决策"""
|
||||
ProjectInvestmentDecision.model_validate(data)
|
||||
request_data = {"push_id": push_id, "biz_id": biz_id, "data": data}
|
||||
request_data = {"push_id": push_id, "biz_id": biz_id, "data": data, "steps": steps or []}
|
||||
response = await client.request(method="PUT", endpoint="/project/investment_decision", data=request_data)
|
||||
if response.get("code") != 200:
|
||||
raise Exception(f"API error: {response.get('message', 'Unknown error')}")
|
||||
|
||||
|
||||
async def api_update_project_dynamic_investment(client, data: Dict[str, Any], push_id: str, biz_id: str) -> None:
|
||||
async def api_update_project_dynamic_investment(client, data: Dict[str, Any], push_id: str, biz_id: str, *, steps: List[Dict[str, Any]] | None = None) -> None:
|
||||
"""PUT /project/dynamic_investment - 更新动态投资"""
|
||||
ProjectDynamicInvestment.model_validate(data)
|
||||
request_data = {"push_id": push_id, "biz_id": biz_id, "data": data}
|
||||
request_data = {"push_id": push_id, "biz_id": biz_id, "data": data, "steps": steps or []}
|
||||
response = await client.request(method="PUT", endpoint="/project/dynamic_investment", data=request_data)
|
||||
if response.get("code") != 200:
|
||||
raise Exception(f"API error: {response.get('message', 'Unknown error')}")
|
||||
@@ -447,10 +466,10 @@ async def api_update_project_dynamic_investment(client, data: Dict[str, Any], pu
|
||||
|
||||
|
||||
|
||||
async def api_update_project_settlement_investment(client, data: Dict[str, Any], push_id: str, biz_id: str) -> None:
|
||||
async def api_update_project_settlement_investment(client, data: Dict[str, Any], push_id: str, biz_id: str, *, steps: List[Dict[str, Any]] | None = None) -> None:
|
||||
"""PUT /project/settlement_investment - 更新结算投资"""
|
||||
ProjectSettlementInvestment.model_validate(data)
|
||||
request_data = {"push_id": push_id, "biz_id": biz_id, "data": data}
|
||||
request_data = {"push_id": push_id, "biz_id": biz_id, "data": data, "steps": steps or []}
|
||||
response = await client.request(method="PUT", endpoint="/project/settlement_investment", data=request_data)
|
||||
if response.get("code") != 200:
|
||||
raise Exception(f"API error: {response.get('message', 'Unknown error')}")
|
||||
|
||||
@@ -171,7 +171,9 @@ class ProjectDetailApiHandler(BaseApiHandler):
|
||||
if origin_payload is None:
|
||||
origin_payload = {}
|
||||
|
||||
if not force_execute and not self._payload_changed(schema, new_payload, origin_payload):
|
||||
force_steps_update = self._steps_changed(node)
|
||||
steps_payload = self._get_request_steps(node)
|
||||
if not force_execute and not force_steps_update and not self._payload_changed(schema, new_payload, origin_payload):
|
||||
reason = f"No physical diff found for project_detail {key} despite strategy update request (Normalization Discrepancy)."
|
||||
print(f" [WARNING] {reason}")
|
||||
# 记录为跳过
|
||||
@@ -192,7 +194,7 @@ class ProjectDetailApiHandler(BaseApiHandler):
|
||||
}
|
||||
|
||||
try:
|
||||
await api_func(self.api_client, new_payload, push_id, biz_id)
|
||||
await api_func(self.api_client, new_payload, push_id, biz_id, steps=steps_payload)
|
||||
results.append(
|
||||
TaskResult.in_progress(
|
||||
node_id=node.node_id,
|
||||
@@ -202,6 +204,7 @@ class ProjectDetailApiHandler(BaseApiHandler):
|
||||
key=str(key),
|
||||
)
|
||||
)
|
||||
self._mark_approval_snapshot_synced(node)
|
||||
except Exception as e:
|
||||
self._pending_push_context.pop(push_id, None)
|
||||
results.append(TaskResult.failed(node_id=node.node_id, error=str(e)))
|
||||
@@ -501,55 +504,55 @@ class ProjectDetailApiHandler(BaseApiHandler):
|
||||
|
||||
# ========== 静态 API 函数(可抽成 SDK) ==========
|
||||
|
||||
async def api_update_project_plan_construction(client, data: Dict[str, Any], push_id: str, biz_id: str) -> None:
|
||||
async def api_update_project_plan_construction(client, data: Dict[str, Any], push_id: str, biz_id: str, *, steps: List[Dict[str, Any]] | None = None) -> None:
|
||||
"""PUT /project/plan_construction - 更新计划施工"""
|
||||
ProjectPlanConstruction.model_validate(data)
|
||||
request_data = {"push_id": push_id, "biz_id": biz_id, "data": data}
|
||||
request_data = {"push_id": push_id, "biz_id": biz_id, "data": data, "steps": steps or []}
|
||||
response = await client.request(method="PUT", endpoint="/project/plan_construction", data=request_data)
|
||||
if response.get("code") != 200:
|
||||
raise Exception(f"API error: {response.get('message', 'Unknown error')}")
|
||||
|
||||
|
||||
async def api_update_project_actual_construction(client, data: Dict[str, Any], push_id: str, biz_id: str) -> None:
|
||||
async def api_update_project_actual_construction(client, data: Dict[str, Any], push_id: str, biz_id: str, *, steps: List[Dict[str, Any]] | None = None) -> None:
|
||||
"""PUT /project/actual_construction - 更新实际施工"""
|
||||
ProjectActualConstruction.model_validate(data)
|
||||
request_data = {"push_id": push_id, "biz_id": biz_id, "data": data}
|
||||
request_data = {"push_id": push_id, "biz_id": biz_id, "data": data, "steps": steps or []}
|
||||
response = await client.request(method="PUT", endpoint="/project/actual_construction", data=request_data)
|
||||
if response.get("code") != 200:
|
||||
raise Exception(f"API error: {response.get('message', 'Unknown error')}")
|
||||
|
||||
|
||||
async def api_update_project_ensure_capacity(client, data: Dict[str, Any], push_id: str, biz_id: str) -> None:
|
||||
async def api_update_project_ensure_capacity(client, data: Dict[str, Any], push_id: str, biz_id: str, *, steps: List[Dict[str, Any]] | None = None) -> None:
|
||||
"""PUT /project/ensure_capacity - 更新确保产能"""
|
||||
ProjectEnsureCapacity.model_validate(data)
|
||||
request_data = {"push_id": push_id, "biz_id": biz_id, "data": data}
|
||||
request_data = {"push_id": push_id, "biz_id": biz_id, "data": data, "steps": steps or []}
|
||||
response = await client.request(method="PUT", endpoint="/project/ensure_capacity", data=request_data)
|
||||
if response.get("code") != 200:
|
||||
raise Exception(f"API error: {response.get('message', 'Unknown error')}")
|
||||
|
||||
|
||||
async def api_update_project_climb_capacity(client, data: Dict[str, Any], push_id: str, biz_id: str) -> None:
|
||||
async def api_update_project_climb_capacity(client, data: Dict[str, Any], push_id: str, biz_id: str, *, steps: List[Dict[str, Any]] | None = None) -> None:
|
||||
"""PUT /project/climb_capacity - 更新登高产能"""
|
||||
ProjectClimbCapacity.model_validate(data)
|
||||
request_data = {"push_id": push_id, "biz_id": biz_id, "data": data}
|
||||
request_data = {"push_id": push_id, "biz_id": biz_id, "data": data, "steps": steps or []}
|
||||
response = await client.request(method="PUT", endpoint="/project/climb_capacity", data=request_data)
|
||||
if response.get("code") != 200:
|
||||
raise Exception(f"API error: {response.get('message', 'Unknown error')}")
|
||||
|
||||
|
||||
async def api_update_project_challenge_capacity(client, data: Dict[str, Any], push_id: str, biz_id: str) -> None:
|
||||
async def api_update_project_challenge_capacity(client, data: Dict[str, Any], push_id: str, biz_id: str, *, steps: List[Dict[str, Any]] | None = None) -> None:
|
||||
"""PUT /project/challenge_capacity - 更新揭榜产能"""
|
||||
ProjectChallengeCapacity.model_validate(data)
|
||||
request_data = {"push_id": push_id, "biz_id": biz_id, "data": data}
|
||||
request_data = {"push_id": push_id, "biz_id": biz_id, "data": data, "steps": steps or []}
|
||||
response = await client.request(method="PUT", endpoint="/project/challenge_capacity", data=request_data)
|
||||
if response.get("code") != 200:
|
||||
raise Exception(f"API error: {response.get('message', 'Unknown error')}")
|
||||
|
||||
|
||||
async def api_update_project_production_capacity(client, data: Dict[str, Any], push_id: str, biz_id: str) -> None:
|
||||
async def api_update_project_production_capacity(client, data: Dict[str, Any], push_id: str, biz_id: str, *, steps: List[Dict[str, Any]] | None = None) -> None:
|
||||
"""PUT /project/production_capacity - 更新投产数据"""
|
||||
ProjectProductionCapacity.model_validate(data)
|
||||
request_data = {"push_id": push_id, "biz_id": biz_id, "data": data}
|
||||
request_data = {"push_id": push_id, "biz_id": biz_id, "data": data, "steps": steps or []}
|
||||
response = await client.request(method="PUT", endpoint="/project/production_capacity", data=request_data)
|
||||
if response.get("code") != 200:
|
||||
raise Exception(f"API error: {response.get('message', 'Unknown error')}")
|
||||
|
||||
@@ -17,7 +17,7 @@ class SupplierSyncStrategy(DefaultSyncStrategy[SupplierDetailResponse]):
|
||||
|
||||
default_config = StrategyConfig(
|
||||
auto_bind=True,
|
||||
auto_bind_fields=["credit_code"],
|
||||
auto_bind_fields=["code"],
|
||||
depend_fields={},
|
||||
local_orphan_action=OrphanAction.NONE,
|
||||
remote_orphan_action=OrphanAction.CREATE_LOCAL,
|
||||
@@ -29,6 +29,7 @@ class SupplierSyncStrategy(DefaultSyncStrategy[SupplierDetailResponse]):
|
||||
source_node,
|
||||
target_node,
|
||||
resolved_data=None,
|
||||
data_id_map=None,
|
||||
) -> bool:
|
||||
"""Supplier 更新忽略 id 字段差异。"""
|
||||
if resolved_data is None:
|
||||
|
||||
@@ -93,7 +93,13 @@ class UnitsApiHandler(BaseApiHandler):
|
||||
continue
|
||||
|
||||
origin_data = node.get_origin_data() or {}
|
||||
update_data = self._filter_update_data(node_data, origin_data, PostGeneratorUnits)
|
||||
force_steps_update = self._steps_changed(node)
|
||||
update_data = self._filter_update_data(
|
||||
node_data,
|
||||
origin_data,
|
||||
PostGeneratorUnits,
|
||||
force_full_schema=force_steps_update,
|
||||
)
|
||||
if not update_data:
|
||||
reason = f"No physical diff found for units {node.data_id} despite strategy update request (Normalization Discrepancy)."
|
||||
print(f" [WARNING] [units] {reason}")
|
||||
@@ -114,7 +120,14 @@ class UnitsApiHandler(BaseApiHandler):
|
||||
continue
|
||||
|
||||
try:
|
||||
await api_update_units(self.api_client, update_model, push_id, biz_id)
|
||||
await api_update_units(
|
||||
self.api_client,
|
||||
update_model,
|
||||
push_id,
|
||||
biz_id,
|
||||
steps=self._get_request_steps(node),
|
||||
)
|
||||
self._mark_approval_snapshot_synced(node)
|
||||
results.append(TaskResult.success(node_id=node.node_id))
|
||||
except Exception as e:
|
||||
results.append(TaskResult.failed(node_id=node.node_id, error=str(e)))
|
||||
@@ -143,7 +156,14 @@ class UnitsApiHandler(BaseApiHandler):
|
||||
|
||||
# ========== 静态 API 函数 ==========
|
||||
|
||||
async def api_update_units(client, data: PostGeneratorUnits, push_id: str, biz_id: str) -> None:
|
||||
async def api_update_units(
|
||||
client,
|
||||
data: PostGeneratorUnits,
|
||||
push_id: str,
|
||||
biz_id: str,
|
||||
*,
|
||||
steps: List[Dict[str, Any]] | None = None,
|
||||
) -> None:
|
||||
"""
|
||||
PUT /units - 更新机组数据
|
||||
|
||||
@@ -153,7 +173,7 @@ async def api_update_units(client, data: PostGeneratorUnits, push_id: str, biz_i
|
||||
push_id: 推送ID
|
||||
biz_id: 业务ID
|
||||
"""
|
||||
request_data = {"push_id": push_id, "biz_id": biz_id, "data": data.model_dump(exclude_unset=True)}
|
||||
request_data = {"push_id": push_id, "biz_id": biz_id, "data": data.model_dump(exclude_unset=True), "steps": steps or []}
|
||||
response = await client.request(method="PUT", endpoint="/units", data=request_data)
|
||||
if response.get("code") != 200:
|
||||
raise Exception(f"API error: {response.get('message', 'Unknown error')}")
|
||||
|
||||
Reference in New Issue
Block a user