summaryrefslogtreecommitdiff
path: root/lib
diff options
context:
space:
mode:
authorjoonhoekim <26rote@gmail.com>2025-10-03 15:39:55 +0900
committerjoonhoekim <26rote@gmail.com>2025-10-03 15:39:55 +0900
commit9eec700c9627d91aaf52a89d1bfb0ae0e21eb49a (patch)
tree2f997ba959fffda0b7bb43e4ec51885c7c4cb24b /lib
parent6cd69b11dc3cedc3ec1e481f1404bd2ce9a64d11 (diff)
(김준회) 유저 정보 동기화 관련 nonsapUserId 기준 통일
Diffstat (limited to 'lib')
-rw-r--r--lib/knox-sync/employee-sync-service.ts6
-rw-r--r--lib/shi-api/shi-api-utils.ts47
2 files changed, 40 insertions, 13 deletions
diff --git a/lib/knox-sync/employee-sync-service.ts b/lib/knox-sync/employee-sync-service.ts
index b7f2a323..3055e1ef 100644
--- a/lib/knox-sync/employee-sync-service.ts
+++ b/lib/knox-sync/employee-sync-service.ts
@@ -265,13 +265,17 @@ async function syncEmployeesToUsers(): Promise<void> {
if (existingUsers.length > 0) {
// 기존 사용자 업데이트
+ // ⚠️ 주의: 기존 사용자의 domain은 유지 (덮어쓰지 않음)
+ const existingDomain = existingUsers[0].domain;
+
await db
.update(users)
.set({
name: employee.fullName,
deptCode: employee.departmentCode,
deptName: employee.departmentName,
- domain: assignedDomain as UserDomainType,
+ // domain은 기존 값 유지 (assignedDomain으로 덮어쓰지 않음)
+ domain: existingDomain,
epId: employee.epId,
updatedAt: new Date(),
})
diff --git a/lib/shi-api/shi-api-utils.ts b/lib/shi-api/shi-api-utils.ts
index e3ab1102..2203f6b2 100644
--- a/lib/shi-api/shi-api-utils.ts
+++ b/lib/shi-api/shi-api-utils.ts
@@ -94,31 +94,33 @@ export const getAllNonsapUser = async () => {
debugLog(`[CHUNK ${Math.floor(i/CHUNK_SIZE) + 1}] Processing ${chunk.length} users (${i + 1}-${Math.min(i + chunk.length, sourceData.length)}/${sourceData.length})`);
try {
- // 청크 내 이메일별 기존 domain 정보 조회를 위한 Map 생성
+ // 청크 내 nonsapUserId별 기존 domain 정보 조회를 위한 Map 생성
const existingDomainMap = new Map<string, string>();
// 각 사용자에 대해 개별적으로 기존 domain 조회 (메모리 효율성 위해)
for (const u of chunk) {
- if (u.EMAIL_ADR) {
+ if (u.USR_ID) {
try {
const existingUser = await db
.select({ domain: users.domain })
.from(users)
- .where(eq(users.email, u.EMAIL_ADR))
+ .where(eq(users.nonsapUserId, u.USR_ID))
.limit(1);
if (existingUser.length > 0) {
- existingDomainMap.set(u.EMAIL_ADR.toLowerCase(), existingUser[0].domain);
+ existingDomainMap.set(u.USR_ID, existingUser[0].domain);
}
} catch (error) {
// 조회 실패 시 무시하고 계속 진행
- console.warn(`Failed to lookup existing user for email ${u.EMAIL_ADR}:`, error);
+ console.warn(`Failed to lookup existing user for nonsapUserId ${u.USR_ID}:`, error);
}
}
}
// 청크 단위로 매핑 수행
const mappedChunk: InsertUser[] = [];
+ const seenNonsapUserIds = new Set<string>(); // 청크 내 중복 체크용
+ const seenEmails = new Set<string>(); // 청크 내 중복 체크용
for (const u of chunk) {
const isDeleted = ynToBool(u.DEL_YN); // nonsap user 테이블에서 삭제여부
@@ -128,9 +130,10 @@ export const getAllNonsapUser = async () => {
// S = 정직원
const isRegularEmployee = (u.REGL_ORORD_GB || '').toUpperCase() === 'S';
- // 기존 사용자인지 확인하여 domain 결정
+ // 기존 사용자인지 확인하여 domain 결정 (nonsapUserId 기준)
const email = u.EMAIL_ADR;
- const existingDomain = email ? existingDomainMap.get(email.toLowerCase()) as UserDomain | undefined : undefined;
+ const nonsapUserId = u.USR_ID;
+ const existingDomain = nonsapUserId ? existingDomainMap.get(nonsapUserId) as UserDomain | undefined : undefined;
// 기존 사용자(existingDomain !== undefined)는 기존 domain을 무조건 유지, 새 사용자는 pending
const domain = existingDomain !== undefined ? existingDomain : 'pending';
@@ -152,18 +155,38 @@ export const getAllNonsapUser = async () => {
isRegularEmployee,
};
- // 필수 필드 검증 (기본적인 검증만 수행)
- if (mappedUser.nonsapUserId) {
- mappedChunk.push(mappedUser as InsertUser);
- } else {
+ // 필수 필드 검증 및 중복 체크
+ if (!mappedUser.nonsapUserId || !mappedUser.email) {
totalSkipped++;
+ debugWarn(`[CHUNK ${Math.floor(i/CHUNK_SIZE) + 1}] 필수 필드 누락: nonsapUserId=${mappedUser.nonsapUserId}, email=${mappedUser.email}`);
+ continue;
}
+
+ // 청크 내 중복 체크
+ if (seenNonsapUserIds.has(mappedUser.nonsapUserId)) {
+ totalSkipped++;
+ debugWarn(`[CHUNK ${Math.floor(i/CHUNK_SIZE) + 1}] 중복 nonsapUserId 발견 (청크 내): ${mappedUser.nonsapUserId}, 이메일: ${mappedUser.email}`);
+ continue;
+ }
+
+ if (seenEmails.has(mappedUser.email.toLowerCase())) {
+ totalSkipped++;
+ debugWarn(`[CHUNK ${Math.floor(i/CHUNK_SIZE) + 1}] 중복 email 발견 (청크 내): ${mappedUser.email}, nonsapUserId: ${mappedUser.nonsapUserId}`);
+ continue;
+ }
+
+ // 중복 체크 통과 시 추가
+ seenNonsapUserIds.add(mappedUser.nonsapUserId);
+ seenEmails.add(mappedUser.email.toLowerCase());
+ mappedChunk.push(mappedUser as InsertUser);
}
// 매핑된 청크가 있을 경우에만 DB 처리 (트랜잭션으로 처리)
if (mappedChunk.length > 0) {
await db.transaction(async (tx) => {
- await bulkUpsert(tx, users, mappedChunk, 'email', 200); // 청크 내에서도 200개씩 세분화
+ // nonsapUserId를 기준으로 UPSERT (진정한 사용자 고유 ID)
+ // email은 변경될 수 있지만 nonsapUserId는 변경되지 않음
+ await bulkUpsert(tx, users, mappedChunk, 'nonsapUserId', 200); // 청크 내에서도 200개씩 세분화
});
totalUpserted += mappedChunk.length;