From 7d6ac687da9e0cf714185feaeced2eede6adb6c2 Mon Sep 17 00:00:00 2001 From: Marsway Date: Wed, 4 Mar 2026 14:00:33 +0800 Subject: [PATCH] fixing --- extensions/sync_ehr_to_oa/job.py | 62 ++++++++++++++++++++++---------- 1 file changed, 44 insertions(+), 18 deletions(-) diff --git a/extensions/sync_ehr_to_oa/job.py b/extensions/sync_ehr_to_oa/job.py index f2342e3..3d5fff1 100644 --- a/extensions/sync_ehr_to_oa/job.py +++ b/extensions/sync_ehr_to_oa/job.py @@ -79,6 +79,23 @@ def _normalize_job_no(v: Any) -> str: return s.upper() +def _to_int_candidate(v: Any) -> int | None: + if v is None: + return None + if isinstance(v, dict): + v = _cell_value(v) + s = str(v).strip() + if not s: + return None + try: + # 兼容 "123.0" + if "." in s and s.endswith(".0"): + return int(float(s)) + return int(s) + except Exception: + return None + + def _extract_oa_row_id_and_fields(row: dict[str, Any]) -> tuple[int | None, dict[str, Any]]: """ 兼容不同 OA export 返回结构,提取: @@ -94,14 +111,20 @@ def _extract_oa_row_id_and_fields(row: dict[str, Any]) -> tuple[int | None, dict for k, v in master.items(): if isinstance(k, str) and k.startswith("field"): field_map[k] = v - for candidate in (row.get("id"), row.get("masterDataId"), master.get("id")): - if candidate is None: - continue - try: - row_id = int(str(candidate)) + # 常见主键位置优先尝试 + for candidate in ( + row.get("id"), + row.get("masterDataId"), + master.get("id"), + master.get("ID"), + master.get("recordId"), + master.get("dataId"), + master.get("_id"), + ): + rid = _to_int_candidate(candidate) + if rid is not None: + row_id = rid break - except Exception: - continue # 结构 B:masterTable.record.fields = [{name,value,showValue}, ...] master_table = row.get("masterTable") @@ -117,12 +140,7 @@ def _extract_oa_row_id_and_fields(row: dict[str, Any]) -> tuple[int | None, dict if name: field_map[name] = fld if row_id is None: - rid = record.get("id") - if rid is not None: - try: - row_id = int(str(rid)) - except Exception: - pass + row_id = _to_int_candidate(record.get("id")) # 结构 C:行级 fields 列表 row_fields = row.get("fields") @@ -351,6 +369,8 @@ class SyncEhrToOaFormJob(BaseJob): oa_id_by_job_no: dict[str, int] = {} oa_id_by_job_no_norm: dict[str, int] = {} row_parse_miss = 0 + row_id_fallback_count = 0 + row_id_fallback_samples: list[str] = [] for row in rows: if not isinstance(row, dict): continue @@ -368,24 +388,30 @@ class SyncEhrToOaFormJob(BaseJob): continue if row_id is None: - row_parse_miss += 1 - if verbose_trace and row_parse_miss <= 20: + # 某些 OA export 不返回主键 id;此时依赖 uniqueFiled(工号) 进行更新匹配。 + row_id = 0 + row_id_fallback_count += 1 + if len(row_id_fallback_samples) < 20: + row_id_fallback_samples.append(job_no) + if verbose_trace and row_id_fallback_count <= 20: logger.info( - "OA 行解析未取到记录ID:job_no=%s row_keys=%s", + "OA 行解析未取到记录ID,使用回退ID=0:job_no=%s row_keys=%s", job_no, list(row.keys())[:20], ) - continue oa_id_by_job_no[job_no] = row_id job_no_norm = _normalize_job_no(job_no) if job_no_norm: oa_id_by_job_no_norm[job_no_norm] = row_id logger.info( - "OA 工号索引完成:indexed_job_numbers=%s indexed_job_numbers_norm=%s parse_miss=%s", + "OA 工号索引完成:indexed_job_numbers=%s indexed_job_numbers_norm=%s parse_miss=%s id_fallback=%s", len(oa_id_by_job_no), len(oa_id_by_job_no_norm), row_parse_miss, + row_id_fallback_count, ) + if row_id_fallback_samples: + logger.info("OA 记录ID回退样本(前20):%s", row_id_fallback_samples) if verbose_trace: for job_no, row_id in list(oa_id_by_job_no.items()): logger.info("OA 工号索引明细:raw=%s norm=%s row_id=%s", job_no, _normalize_job_no(job_no), row_id)