update
This commit is contained in:
parent
90a54a8dd8
commit
ecc79128f6
|
|
@ -46,6 +46,19 @@ def _custom_prop_value(custom_props: Any, key: str | None) -> str:
|
||||||
return str(raw or "").strip()
|
return str(raw or "").strip()
|
||||||
|
|
||||||
|
|
||||||
|
def _to_bool_or_none(v: Any) -> bool | None:
|
||||||
|
if v is None:
|
||||||
|
return None
|
||||||
|
if isinstance(v, bool):
|
||||||
|
return v
|
||||||
|
s = str(v).strip().lower()
|
||||||
|
if s in ("1", "true", "yes", "y", "on"):
|
||||||
|
return True
|
||||||
|
if s in ("0", "false", "no", "n", "off", ""):
|
||||||
|
return False
|
||||||
|
return bool(v)
|
||||||
|
|
||||||
|
|
||||||
def _choose_better_record(current: dict[str, Any], candidate: dict[str, Any]) -> dict[str, Any]:
|
def _choose_better_record(current: dict[str, Any], candidate: dict[str, Any]) -> dict[str, Any]:
|
||||||
def _score(item: dict[str, Any]) -> str:
|
def _score(item: dict[str, Any]) -> str:
|
||||||
record = item.get("recordInfo") or {}
|
record = item.get("recordInfo") or {}
|
||||||
|
|
@ -150,15 +163,43 @@ class SyncEhrToOaFormJob(BaseJob):
|
||||||
continue
|
continue
|
||||||
existing = ehr_by_job_no.get(job_no)
|
existing = ehr_by_job_no.get(job_no)
|
||||||
ehr_by_job_no[job_no] = item if existing is None else _choose_better_record(existing, item)
|
ehr_by_job_no[job_no] = item if existing is None else _choose_better_record(existing, item)
|
||||||
|
logger.info(
|
||||||
|
"EHR 数据准备完成:employee_rows=%s organization_rows=%s distinct_job_numbers=%s",
|
||||||
|
len(emp_rows),
|
||||||
|
len(org_rows),
|
||||||
|
len(ehr_by_job_no),
|
||||||
|
)
|
||||||
|
|
||||||
# 4) 导出 OA 表单,建立字段映射 + 工号到记录ID映射
|
# 4) 导出 OA 表单,建立字段映射 + 工号到记录ID映射
|
||||||
exp_resp = seeyon.export_cap4_form_soap(templateCode=oa_template_code, senderLoginName=sender_login_name, rightId=oa_right_id)
|
exp_resp = seeyon.export_cap4_form_soap(
|
||||||
|
templateCode=oa_template_code,
|
||||||
|
senderLoginName=sender_login_name,
|
||||||
|
rightId=oa_right_id,
|
||||||
|
)
|
||||||
raw = exp_resp.text or ""
|
raw = exp_resp.text or ""
|
||||||
|
logger.info(
|
||||||
|
"OA export 返回:status=%s content_length=%s template=%s",
|
||||||
|
exp_resp.status_code,
|
||||||
|
len(raw),
|
||||||
|
oa_template_code,
|
||||||
|
)
|
||||||
|
if raw:
|
||||||
|
logger.info("OA export 响应预览:%s", raw[:1000])
|
||||||
|
try:
|
||||||
payload = json.loads(raw) if raw else {}
|
payload = json.loads(raw) if raw else {}
|
||||||
|
except Exception as e: # noqa: BLE001
|
||||||
|
raise RuntimeError(f"OA export 响应不是有效 JSON: err={e!r} preview={raw[:500]!r}") from e
|
||||||
|
|
||||||
|
export_code = payload.get("code")
|
||||||
|
export_message = payload.get("message")
|
||||||
|
if export_code not in (None, 0, "0"):
|
||||||
|
raise RuntimeError(f"OA export failed code={export_code!r} message={export_message!r}")
|
||||||
outer = payload.get("data") or {}
|
outer = payload.get("data") or {}
|
||||||
form = outer.get("data") or {}
|
form = outer.get("data") or {}
|
||||||
if not isinstance(form, dict):
|
if not isinstance(form, dict):
|
||||||
raise RuntimeError("OA export invalid: data.data is not an object")
|
raise RuntimeError(
|
||||||
|
f"OA export invalid: data.data is not an object; payload_keys={list(payload.keys())[:20]}"
|
||||||
|
)
|
||||||
|
|
||||||
definition = form.get("definition") or {}
|
definition = form.get("definition") or {}
|
||||||
fields = definition.get("fields") or []
|
fields = definition.get("fields") or []
|
||||||
|
|
@ -209,6 +250,12 @@ class SyncEhrToOaFormJob(BaseJob):
|
||||||
oa_master_table_name = str(master_tbl.get("name") or "").strip()
|
oa_master_table_name = str(master_tbl.get("name") or "").strip()
|
||||||
if not oa_master_table_name:
|
if not oa_master_table_name:
|
||||||
raise RuntimeError("public_cfg.oa_master_table_name is required (cannot infer from OA export)")
|
raise RuntimeError("public_cfg.oa_master_table_name is required (cannot infer from OA export)")
|
||||||
|
logger.info(
|
||||||
|
"OA 表单解析完成:template=%s master_table=%s form_rows=%s",
|
||||||
|
oa_template_code,
|
||||||
|
oa_master_table_name,
|
||||||
|
len(rows),
|
||||||
|
)
|
||||||
|
|
||||||
job_field_code = display_to_code["工号"]
|
job_field_code = display_to_code["工号"]
|
||||||
oa_id_by_job_no: dict[str, int] = {}
|
oa_id_by_job_no: dict[str, int] = {}
|
||||||
|
|
@ -234,6 +281,7 @@ class SyncEhrToOaFormJob(BaseJob):
|
||||||
except Exception:
|
except Exception:
|
||||||
continue
|
continue
|
||||||
oa_id_by_job_no[job_no] = row_id
|
oa_id_by_job_no[job_no] = row_id
|
||||||
|
logger.info("OA 工号索引完成:indexed_job_numbers=%s", len(oa_id_by_job_no))
|
||||||
|
|
||||||
# 5) 组装批量更新数据
|
# 5) 组装批量更新数据
|
||||||
data_list: list[dict[str, Any]] = []
|
data_list: list[dict[str, Any]] = []
|
||||||
|
|
@ -295,11 +343,21 @@ class SyncEhrToOaFormJob(BaseJob):
|
||||||
"subTables": [],
|
"subTables": [],
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
logger.info(
|
||||||
|
"待更新数据准备完成:prepared_updates=%s not_found_in_oa=%s",
|
||||||
|
len(data_list),
|
||||||
|
not_found_in_oa,
|
||||||
|
)
|
||||||
|
if not data_list:
|
||||||
|
raise RuntimeError(
|
||||||
|
"No updates prepared for OA batch-update (check jobNumber matching between EHR and OA, and form field mapping)"
|
||||||
|
)
|
||||||
|
|
||||||
# 6) 分批执行 batch-update
|
# 6) 分批执行 batch-update
|
||||||
success_count = 0
|
success_count = 0
|
||||||
failed_count = 0
|
failed_count = 0
|
||||||
failed_data: dict[str, str] = {}
|
failed_data: dict[str, str] = {}
|
||||||
|
do_trigger_bool = _to_bool_or_none(do_trigger)
|
||||||
for i in range(0, len(data_list), batch_size):
|
for i in range(0, len(data_list), batch_size):
|
||||||
chunk = data_list[i : i + batch_size]
|
chunk = data_list[i : i + batch_size]
|
||||||
resp = seeyon.batch_update_cap4_form_soap(
|
resp = seeyon.batch_update_cap4_form_soap(
|
||||||
|
|
@ -308,7 +366,7 @@ class SyncEhrToOaFormJob(BaseJob):
|
||||||
rightId=oa_right_id,
|
rightId=oa_right_id,
|
||||||
dataList=chunk,
|
dataList=chunk,
|
||||||
uniqueFiled=[job_field_code],
|
uniqueFiled=[job_field_code],
|
||||||
doTrigger=bool(do_trigger) if do_trigger is not None else None,
|
doTrigger=do_trigger_bool,
|
||||||
)
|
)
|
||||||
rj = resp.json() if resp.content else {}
|
rj = resp.json() if resp.content else {}
|
||||||
code = int(rj.get("code", -1))
|
code = int(rj.get("code", -1))
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue