支持企微通讯录缺失手机号(07-26-internal-ops-recovery-baseline)

这个提交包含在:
2026-07-27 13:05:27 +08:00
父节点 9875bc37a4
当前提交 2526052e73
共修改 24 个文件,包含 845 行新增和 63 行删除
@@ -468,7 +468,7 @@ function normalizeWecomHrProfile({ contact = {}, staff = {}, departmentMap = new
};
profile.missingRequiredFields = [];
for (const field of ["externalUserId", "name", "phone", "email"]) {
for (const field of ["externalUserId", "name", "email"]) {
if (!isMeaningfulString(profile[field])) profile.missingRequiredFields.push(field);
}
if (!isMeaningfulString(profile.departmentExternalId) && !isMeaningfulString(profile.departmentName)) {
@@ -721,18 +721,21 @@ async function detectUniqueConflicts(prisma, employeeId, profile) {
function buildEmployeeChanges(employee, profile, department) {
if (!employee) {
return {
const changes = {
name: buildChange("name", null, profile.name),
phone: buildChange("phone", null, profile.phone),
email: buildChange("email", null, profile.email),
department: buildChange("department", null, department.name),
title: buildChange("title", null, profile.title),
};
if (profile.phone) changes.phone = buildChange("phone", null, profile.phone);
return changes;
}
const changes = {};
if (employee.name !== profile.name) changes.name = buildChange("name", employee.name, profile.name);
if (employee.phone !== profile.phone) changes.phone = buildChange("phone", employee.phone, profile.phone);
if (profile.phone && employee.phone !== profile.phone) {
changes.phone = buildChange("phone", employee.phone, profile.phone);
}
if (employee.email !== profile.email) changes.email = buildChange("email", employee.email, profile.email);
if (department.id && employee.department_id !== department.id) {
changes.department = buildChange("department", employee.department_id, department.name);
@@ -854,7 +857,7 @@ async function processProfile(prisma, runId, profile, context) {
where: { id: existing.id },
data: {
name: profile.name,
phone: profile.phone,
...(profile.phone ? { phone: profile.phone } : {}),
email: profile.email,
department_id: department.id,
title: profile.title,
@@ -866,7 +869,7 @@ async function processProfile(prisma, runId, profile, context) {
: await prisma.employee.create({
data: {
name: profile.name,
phone: profile.phone,
phone: profile.phone || null,
email: profile.email,
department_id: department.id,
title: profile.title,
@@ -1077,6 +1080,8 @@ async function runWecomHrMasterSync({
userids: rawUserids,
limit: rawLimit,
fetchImpl = fetch,
sourceProfiles = null,
sourceLabel = "manual_export",
}) {
const mode = normalizeMode(rawMode);
const userids = normalizeUserids(rawUserids);
@@ -1095,12 +1100,17 @@ async function runWecomHrMasterSync({
let source = null;
try {
source = await fetchWecomHrProfiles({
config,
userids,
limit,
fetchImpl,
});
source = Array.isArray(sourceProfiles)
? {
profiles: sourceProfiles.slice(0, limit),
tokenSource: { offline: toSafeString(sourceLabel, 40) || "manual_export" },
}
: await fetchWecomHrProfiles({
config,
userids,
limit,
fetchImpl,
});
} catch (error) {
const status = error instanceof WecomHrMasterSyncError && error.code === "wecom_token_unavailable"
? "skipped"
@@ -115,7 +115,7 @@ async function fetchWecomOAuthOnboardingProfile({
};
const missing = [];
for (const field of ["name", "phone", "email", "departmentExternalId", "departmentName"]) {
for (const field of ["name", "email", "departmentExternalId", "departmentName"]) {
if (!profile[field]) missing.push(field);
}
if (missing.length) {
@@ -186,7 +186,12 @@ async function resolveEmployee(tx, profile) {
},
});
const contactMatches = await tx.employee.findMany({
where: { OR: [{ phone: profile.phone }, { email: profile.email }] },
where: {
OR: [
...(profile.phone ? [{ phone: profile.phone }] : []),
{ email: profile.email },
],
},
select: {
id: true,
status: true,
@@ -229,7 +234,7 @@ async function provisionWecomOAuthEmployee({
where: { id: existing.id },
data: {
name: profile.name,
phone: profile.phone,
...(profile.phone ? { phone: profile.phone } : {}),
email: profile.email,
department_id: departmentId,
title: profile.title,
@@ -241,7 +246,7 @@ async function provisionWecomOAuthEmployee({
: await tx.employee.create({
data: {
name: profile.name,
phone: profile.phone,
phone: profile.phone || null,
email: profile.email,
department_id: departmentId,
title: profile.title,
@@ -294,7 +299,7 @@ async function provisionWecomOAuthEmployee({
extra: {
created: !existing,
source: "wecom_oauth",
fieldPresence: { phone: true, email: true },
fieldPresence: { phone: Boolean(profile.phone), email: true },
},
}),
});