fix(sync): match EHR users by AD account regardless of status
Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
parent
b16764b633
commit
6df400f31d
|
|
@ -418,16 +418,11 @@ def _root_org_name(org: dict[str, Any], org_by_oid: dict[str, dict[str, Any]]) -
|
|||
return last_name
|
||||
|
||||
|
||||
def _is_current_employee(item: dict[str, Any], current_status_values: set[str]) -> bool:
|
||||
def _is_syncable_employee_record(item: dict[str, Any]) -> bool:
|
||||
rec = item.get("recordInfo") or {}
|
||||
emp = item.get("employeeInfo") or {}
|
||||
if not isinstance(rec, dict) or not isinstance(emp, dict):
|
||||
return False
|
||||
if str(rec.get("lastWorkDate") or "").strip():
|
||||
return False
|
||||
status = _field_translate_or_value(item, "EmployeeStatus")
|
||||
if current_status_values and status and status not in current_status_values:
|
||||
return False
|
||||
for key in ("isDeleted", "IsDeleted", "deleted", "disabled", "Disabled"):
|
||||
raw = emp.get(key, rec.get(key))
|
||||
if _to_bool_or_none(raw) is True:
|
||||
|
|
@ -500,14 +495,6 @@ class SyncEhrToAdUserJob(BaseJob):
|
|||
default_company = str(params.get("default_company") or "").strip()
|
||||
target_sam_accounts = _parse_target_sam_accounts(params)
|
||||
|
||||
current_status_values_param = params.get("current_status_values")
|
||||
if isinstance(current_status_values_param, list):
|
||||
current_status_values = {str(x).strip() for x in current_status_values_param if str(x).strip()}
|
||||
elif str(current_status_values_param or "").strip():
|
||||
current_status_values = {x.strip() for x in str(current_status_values_param).split(",") if x.strip()}
|
||||
else:
|
||||
current_status_values = set()
|
||||
|
||||
location_mappings = params.get("location_mappings")
|
||||
location_mappings = location_mappings if isinstance(location_mappings, dict) else None
|
||||
|
||||
|
|
@ -554,7 +541,7 @@ class SyncEhrToAdUserJob(BaseJob):
|
|||
users_by_sam: dict[str, dict[str, Any]] = {}
|
||||
user_id_to_sam: dict[int, str] = {}
|
||||
for item in emp_rows:
|
||||
if not isinstance(item, dict) or not _is_current_employee(item, current_status_values):
|
||||
if not isinstance(item, dict) or not _is_syncable_employee_record(item):
|
||||
continue
|
||||
sam = _field_value(item, domain_account_key)
|
||||
if not sam:
|
||||
|
|
@ -571,7 +558,7 @@ class SyncEhrToAdUserJob(BaseJob):
|
|||
break
|
||||
|
||||
logger.info(
|
||||
"EHR 当前用户准备完成:employee_rows=%s current_with_ad_account=%s org_rows=%s target_sam_accounts=%s",
|
||||
"EHR AD 用户准备完成:employee_rows=%s users_with_ad_account=%s org_rows=%s target_sam_accounts=%s",
|
||||
len(emp_rows),
|
||||
len(users_by_sam),
|
||||
len(org_rows),
|
||||
|
|
@ -760,7 +747,7 @@ class SyncEhrToAdUserJob(BaseJob):
|
|||
"filtered_by_target_sam": bool(target_sam_accounts),
|
||||
"target_sam_accounts": len(target_sam_accounts),
|
||||
"ehr_employee_rows": len(emp_rows),
|
||||
"ehr_current_users_with_ad_account": len(users_by_sam),
|
||||
"ehr_users_with_ad_account": len(users_by_sam),
|
||||
"processed": processed,
|
||||
"updated": updated,
|
||||
"skipped_unchanged": skipped_unchanged,
|
||||
|
|
|
|||
|
|
@ -0,0 +1,59 @@
|
|||
import sys
|
||||
import types
|
||||
import importlib.util
|
||||
from pathlib import Path
|
||||
|
||||
|
||||
ROOT = Path(__file__).resolve().parents[3]
|
||||
sys.path.insert(0, str(ROOT))
|
||||
|
||||
base_module = types.ModuleType("app.jobs.base")
|
||||
|
||||
|
||||
class BaseJob:
|
||||
pass
|
||||
|
||||
|
||||
base_module.BaseJob = BaseJob
|
||||
sys.modules["app.jobs.base"] = base_module
|
||||
|
||||
api_module = types.ModuleType("extensions.sync_ehr_to_ad.api")
|
||||
api_module.ActiveDirectoryClient = object
|
||||
api_module.SyncEhrToAdApi = object
|
||||
sys.modules["extensions.sync_ehr_to_ad.api"] = api_module
|
||||
|
||||
spec = importlib.util.spec_from_file_location("sync_ehr_to_ad_job", ROOT / "extensions/sync_ehr_to_ad/job.py")
|
||||
job_module = importlib.util.module_from_spec(spec)
|
||||
assert spec.loader is not None
|
||||
spec.loader.exec_module(job_module)
|
||||
|
||||
_is_syncable_employee_record = job_module._is_syncable_employee_record
|
||||
|
||||
|
||||
def _ehr_item(*, employee_status="离职", last_work_date="", emp_flags=None, rec_flags=None):
|
||||
emp_flags = emp_flags or {}
|
||||
rec_flags = rec_flags or {}
|
||||
return {
|
||||
"employeeInfo": {
|
||||
"translateProperties": {"EmployeeStatus": employee_status},
|
||||
"customProperties": {"extADAccountName_606508_511687157": "zhangsan"},
|
||||
**emp_flags,
|
||||
},
|
||||
"recordInfo": {
|
||||
"lastWorkDate": last_work_date,
|
||||
**rec_flags,
|
||||
},
|
||||
}
|
||||
|
||||
|
||||
def test_syncable_employee_record_includes_any_employee_status():
|
||||
assert _is_syncable_employee_record(_ehr_item(employee_status="离职")) is True
|
||||
|
||||
|
||||
def test_syncable_employee_record_includes_records_with_last_work_date():
|
||||
assert _is_syncable_employee_record(_ehr_item(last_work_date="2026-07-01")) is True
|
||||
|
||||
|
||||
def test_syncable_employee_record_excludes_deleted_or_disabled_records():
|
||||
assert _is_syncable_employee_record(_ehr_item(emp_flags={"isDeleted": True})) is False
|
||||
assert _is_syncable_employee_record(_ehr_item(rec_flags={"disabled": True})) is False
|
||||
Loading…
Reference in New Issue