问题原因:钉钉应用缺少手机号读取权限,导致返回的员工手机号全为空, 同步逻辑认为"钉钉没有这些员工"而错误删除了系统中的用户。 修复方案: 1. 增加安全检查:如果钉钉返回员工但手机号全为空,跳过删除操作 2. 使用双重匹配:同时考虑手机号和钉钉ID进行员工匹配 3. 增强日志:记录有手机号和钉钉ID的员工数量 4. 增加保护:只有手机号和钉钉ID都不匹配时才删除
This commit is contained in:
@@ -611,7 +611,7 @@ class EmployeeSyncService:
|
||||
"""
|
||||
增量同步员工数据
|
||||
- 新增钉钉有但系统没有的员工
|
||||
- 删除系统有但钉钉没有的员工(物理删除)
|
||||
- 删除系统有但钉钉没有的员工(软删除)
|
||||
- 跳过两边都存在的员工(不做任何修改)
|
||||
|
||||
Returns:
|
||||
@@ -634,8 +634,22 @@ class EmployeeSyncService:
|
||||
try:
|
||||
# 1. 获取钉钉在职员工数据
|
||||
dingtalk_employees = await self.fetch_employees_from_dingtalk()
|
||||
|
||||
# 使用手机号和钉钉ID双重匹配
|
||||
dingtalk_phones = {emp.get('phone') for emp in dingtalk_employees if emp.get('phone')}
|
||||
logger.info(f"钉钉在职员工数量: {len(dingtalk_phones)}")
|
||||
dingtalk_ids = {emp.get('dingtalk_id') for emp in dingtalk_employees if emp.get('dingtalk_id')}
|
||||
|
||||
logger.info(f"钉钉在职员工数量: {len(dingtalk_employees)}")
|
||||
logger.info(f"有手机号的员工: {len(dingtalk_phones)}")
|
||||
logger.info(f"有钉钉ID的员工: {len(dingtalk_ids)}")
|
||||
|
||||
# 安全检查:如果钉钉返回了员工但手机号全为空,可能是权限问题,跳过删除操作
|
||||
skip_delete = False
|
||||
if len(dingtalk_employees) > 0 and len(dingtalk_phones) == 0:
|
||||
logger.warning("⚠️ 钉钉返回员工数据但手机号全为空,可能是钉钉应用缺少手机号读取权限!")
|
||||
logger.warning("⚠️ 跳过离职员工处理,避免误删")
|
||||
skip_delete = True
|
||||
stats['errors'].append("钉钉应用可能缺少手机号读取权限,跳过删除操作")
|
||||
|
||||
# 2. 获取系统现有用户(排除admin和已软删除的)
|
||||
stmt = select(User).where(
|
||||
@@ -645,16 +659,26 @@ class EmployeeSyncService:
|
||||
result = await self.db.execute(stmt)
|
||||
system_users = result.scalars().all()
|
||||
system_phones = {user.phone for user in system_users if user.phone}
|
||||
logger.info(f"系统现有员工数量(排除admin): {len(system_phones)}")
|
||||
system_dingtalk_ids = {user.dingtalk_id for user in system_users if user.dingtalk_id}
|
||||
logger.info(f"系统现有员工数量(排除admin): {len(system_users)}")
|
||||
logger.info(f"系统有手机号的员工: {len(system_phones)}")
|
||||
logger.info(f"系统有钉钉ID的员工: {len(system_dingtalk_ids)}")
|
||||
|
||||
# 3. 计算需要新增、删除、跳过的员工
|
||||
# 3. 计算需要新增、删除、跳过的员工(同时考虑手机号和钉钉ID)
|
||||
# 新增: 钉钉有但系统没有(手机号或钉钉ID都不存在)
|
||||
phones_to_add = dingtalk_phones - system_phones
|
||||
phones_to_delete = system_phones - dingtalk_phones
|
||||
ids_to_add = dingtalk_ids - system_dingtalk_ids
|
||||
|
||||
# 删除: 系统有但钉钉没有(手机号和钉钉ID都不在钉钉列表中)
|
||||
phones_to_delete = system_phones - dingtalk_phones if not skip_delete else set()
|
||||
|
||||
# 跳过: 两边都存在
|
||||
phones_to_skip = dingtalk_phones & system_phones
|
||||
ids_to_skip = dingtalk_ids & system_dingtalk_ids
|
||||
|
||||
logger.info(f"待新增: {len(phones_to_add)}, 待删除: {len(phones_to_delete)}, 跳过: {len(phones_to_skip)}")
|
||||
logger.info(f"待新增(手机号): {len(phones_to_add)}, 待删除(手机号): {len(phones_to_delete)}, 跳过(手机号): {len(phones_to_skip)}")
|
||||
|
||||
stats['skipped_count'] = len(phones_to_skip)
|
||||
stats['skipped_count'] = len(phones_to_skip) + len(ids_to_skip)
|
||||
|
||||
# 4. 新增员工
|
||||
for employee in dingtalk_employees:
|
||||
@@ -724,12 +748,29 @@ class EmployeeSyncService:
|
||||
# 先flush之前的新增操作
|
||||
await self.db.flush()
|
||||
|
||||
# 标记离职员工
|
||||
for user in system_users:
|
||||
if user.phone and user.phone in phones_to_delete:
|
||||
# 如果跳过删除,则不处理
|
||||
if skip_delete:
|
||||
logger.info("⚠️ 由于安全检查未通过,跳过离职员工处理")
|
||||
else:
|
||||
# 标记离职员工(需要手机号和钉钉ID都不在钉钉列表中才删除)
|
||||
for user in system_users:
|
||||
# 双重保护:确保不删除admin
|
||||
if user.username == 'admin' or user.role == 'admin':
|
||||
logger.warning(f"⚠️ 跳过处理管理员账户: {user.username}")
|
||||
continue
|
||||
|
||||
# 检查用户是否在钉钉列表中(手机号或钉钉ID匹配任一即视为在职)
|
||||
in_dingtalk = False
|
||||
if user.phone and user.phone in dingtalk_phones:
|
||||
in_dingtalk = True
|
||||
if user.dingtalk_id and user.dingtalk_id in dingtalk_ids:
|
||||
in_dingtalk = True
|
||||
|
||||
if in_dingtalk:
|
||||
continue # 在钉钉中,跳过
|
||||
|
||||
# 额外安全检查:如果钉钉没有返回有效数据,不删除
|
||||
if len(dingtalk_phones) == 0 and len(dingtalk_ids) == 0:
|
||||
logger.warning(f"⚠️ 钉钉数据为空,跳过删除用户: {user.full_name}")
|
||||
continue
|
||||
|
||||
try:
|
||||
|
||||
Reference in New Issue
Block a user