diff --git a/extensions/sync_ehr_leaves_to_oa/job.py b/extensions/sync_ehr_leaves_to_oa/job.py index b46a942..aad9cfd 100644 --- a/extensions/sync_ehr_leaves_to_oa/job.py +++ b/extensions/sync_ehr_leaves_to_oa/job.py @@ -6,6 +6,8 @@ from datetime import date, datetime from decimal import Decimal, InvalidOperation from typing import Any +import httpx + from app.integrations.seeyon import SeeyonClient from app.jobs.base import BaseJob from extensions.sync_ehr_leaves_to_oa.api import SyncEhrLeavesToOaApi @@ -63,12 +65,12 @@ def _to_decimal(v: Any) -> Decimal: def _decimal_to_str(v: Decimal) -> str: - if v == v.to_integral(): - return str(int(v)) - s = format(v.normalize(), "f") - if "." in s: - s = s.rstrip("0").rstrip(".") - return s + # OA 字段请假天数为 DECIMAL(?,1),统一保留 1 位小数(如 1.0) + try: + q = v.quantize(Decimal("0.1")) + except Exception: + q = Decimal("0.0") + return format(q, "f") def _to_int_safe(v: Any) -> int: @@ -277,9 +279,10 @@ class SyncEhrLeavesToOaMonthJob(BaseJob): to_update = 0 to_insert = 0 for (job_no, leave_date), leave_days in sorted(agg.items(), key=lambda x: (x[0][0], x[0][1])): + leave_date_value = f"{leave_date} 00:00:00" fields_payload = [ {"name": field_job_no, "value": job_no, "showValue": job_no}, - {"name": field_leave_date, "value": leave_date, "showValue": leave_date}, + {"name": field_leave_date, "value": leave_date_value, "showValue": leave_date}, {"name": field_leave_days, "value": _decimal_to_str(leave_days), "showValue": _decimal_to_str(leave_days)}, ] if field_name: @@ -319,14 +322,28 @@ class SyncEhrLeavesToOaMonthJob(BaseJob): chunk = data_list[i : i + batch_size] if not chunk: continue - resp = seeyon.batch_update_cap4_form_soap( - formCode=oa_form_code, - loginName=oa_login_name, - rightId=oa_right_id, - dataList=chunk, - uniqueFiled=None, - doTrigger=do_trigger_bool, - ) + try: + resp = seeyon.batch_update_cap4_form_soap( + formCode=oa_form_code, + loginName=oa_login_name, + rightId=oa_right_id, + dataList=chunk, + uniqueFiled=[field_job_no, field_leave_date], + doTrigger=do_trigger_bool, + ) + except httpx.HTTPStatusError as e: + resp_text = "" + try: + resp_text = str((e.response.text or "")[:2000]) + except Exception: + resp_text = "" + first_row = chunk[0] if chunk else {} + raise RuntimeError( + "OA batch-update HTTP error " + f"status={getattr(e.response, 'status_code', None)!r} " + f"body_preview={resp_text!r} " + f"first_row={json.dumps(first_row, ensure_ascii=False, default=str)[:2000]}" + ) from e rj = resp.json() if resp.content else {} code_local = int(rj.get("code", -1)) if code_local != 0: