from pydantic import BaseModel from ...sync_system.strategy import DefaultSyncStrategy from ...sync_system.config import StrategyConfig, OrphanAction, UpdateDirection from schemas.project.project_base import ProjectResponseBase class ProjectDomainOption(BaseModel): pull_group_plan_production_date: bool = False class ProjectSyncStrategy(DefaultSyncStrategy[ProjectResponseBase]): """ Project 同步策略 业务规则: 1. 手动绑定(根节点) 2. 允许拉取更新(不自动创建) 3. 依赖公司(company) schema 已在类定义中设置,禁止在初始化时传入其他 schema。 """ # 类变量:schema 固定为 ProjectResponseBase schema = ProjectResponseBase domain_option_model = ProjectDomainOption _PULL_ONLY_FIELDS = [ "ic_plan_first_production_date", "ic_plan_full_production_date", ] # 类变量:默认配置 default_config = StrategyConfig( auto_bind=False, auto_bind_fields=[], depend_fields={"company_id": "company"}, local_orphan_action=OrphanAction.CREATE_REMOTE, remote_orphan_action=OrphanAction.NONE, update_direction=UpdateDirection.PUSH, ) @property def domain_option(self) -> ProjectDomainOption: return ProjectDomainOption.model_validate(self.config.domain_option) def get_node_update_payload(self, node): payload = dict(node.get_data() or {}) context = getattr(node, "context", None) if not isinstance(context, dict): return payload all_info = context.get("all_info") if not isinstance(all_info, dict): return payload for section_name, section_data in all_info.items(): if not section_name.endswith("_extension") or not isinstance(section_data, dict): continue for field_name in self._PULL_ONLY_FIELDS: if payload.get(field_name) not in (None, ""): continue if field_name in section_data: payload[field_name] = section_data.get(field_name) return payload async def update_pair(self, local_node, remote_node, data_id_map=None): updated_by_id = {} if self.domain_option.pull_group_plan_production_date: pull_update = await self.prepare_update_for_direction( local_node, remote_node, UpdateDirection.PULL, data_id_map, include_fields=self._PULL_ONLY_FIELDS, ) if pull_update is not None: updated_by_id[pull_update.node_id] = pull_update generic_exclude_fields = self._PULL_ONLY_FIELDS else: generic_exclude_fields = None if self.config.update_direction != UpdateDirection.NONE: generic_update = await self.prepare_update_for_direction( local_node, remote_node, self.config.update_direction, data_id_map, exclude_fields=generic_exclude_fields, ) if generic_update is not None: updated_by_id[generic_update.node_id] = generic_update return list(updated_by_id.values())