'use server'; import { nonsapUser, users } from '@/db/schema'; import db from '@/db/db'; import { sql } from 'drizzle-orm'; import { debugError, debugLog, debugWarn, debugSuccess } from '@/lib/debug-utils'; const shiApiBaseUrl = process.env.SHI_API_BASE_URL; const shiNonsapUserSegment = process.env.SHI_NONSAP_USER_SEGMENT; const shiApiJwtToken = process.env.SHI_API_JWT_TOKEN; type NonsapUser = typeof nonsapUser.$inferSelect; type NonsapUserInsert = typeof nonsapUser.$inferInsert; type InsertUser = typeof users.$inferInsert; export const getAllNonsapUser = async () => { try{ debugLog('Starting NONSAP user sync via SHI-API'); if (!shiApiBaseUrl || !shiNonsapUserSegment || !shiApiJwtToken) { throw new Error('SHI API 환경변수가 설정되지 않았습니다. (SHI_API_BASE_URL, SHI_NONSAP_USER_SEGMENT, SHI_API_JWT_TOKEN)'); } const ynToBool = (value: string | null | undefined) => (value || '').toUpperCase() === 'Y'; // ** 1. 전체 데이터 조회해 응답 받음 (js 배열) ** const response = await fetch(`${shiApiBaseUrl}${shiNonsapUserSegment}`, { headers: { Authorization: `Bearer ${shiApiJwtToken}`, }, cache: 'no-store', }); if (!response.ok) { const text = await response.text().catch(() => ''); throw new Error(`SHI-API 요청 실패: ${response.status} ${response.statusText} ${text}`); } const data: NonsapUser[] = await response.json(); debugSuccess(`[SHI-API] fetched ${Array.isArray(data) ? data.length : 0} users`); // ** 2. 받은 데이터를 DELETE & INSERT 방식으로 수신 테이블 (nonsap-user) 에 저장 ** await db.delete(nonsapUser); // 전체 정리 if (Array.isArray(data) && data.length > 0) { await db.insert(nonsapUser).values(data as unknown as NonsapUserInsert[]); // 데이터 저장 (스키마 컬럼 그대로) debugSuccess(`[STAGE] nonsap_user refreshed with ${data.length} records`); } // ** 3. 데이터 저장 이후, 비즈니스 테이블인 "public"."users" 에 동기화 시킴 (매핑 필요) ** const now = new Date(); const mappedRaw: Partial[] = (Array.isArray(data) ? data : []) .map((u: NonsapUser): Partial => { const isDeleted = ynToBool(u.DEL_YN); // nonsap user 테이블에서 삭제여부 const isAbsent = ynToBool(u.LOFF_GB); // nonsap user 테이블에서 휴직여부 const notApproved = (u.AGR_YN || '').toUpperCase() === 'N'; // nonsap user 테이블에서 승인여부 const isActive = !(isDeleted || isAbsent || notApproved); // eVCP 내에서 활성화 여부 // S = 정직원 const isRegularEmployee = (u.REGL_ORORD_GB || '').toUpperCase() === 'S'; return { // upsert key = USR_ID nonsapUserId: u.USR_ID || undefined, // mapped fields employeeNumber: u.EMPNO || undefined, knoxId: u.MYSNG_ID || undefined, name: u.USR_NM || undefined, email: u.EMAIL_ADR || undefined, epId: u.MYSNG_ID || undefined, deptCode: u.CH_DEPTCD || undefined, deptName: u.CH_DEPTNM || undefined, phone: u.TELNO || undefined, isAbsent, isDeletedOnNonSap: isDeleted, isActive, isRegularEmployee, }; }); // users 테이블 제약조건 대응: email, name 은 not null + nonsapUserId 존재 //.filter((u) => typeof u.email === 'string' && !!u.email && typeof u.name === 'string' && !!u.name && typeof u.nonsapUserId === 'string' && u.nonsapUserId.length > 0); const mappedUsers = mappedRaw as InsertUser[]; if (mappedUsers.length > 0) { await db.insert(users) .values(mappedUsers) .onConflictDoUpdate({ target: users.nonsapUserId, set: { name: sql`excluded.name`, employeeNumber: sql`excluded.employeeNumber`, knoxId: sql`excluded.knoxId`, epId: sql`excluded."epId"`, deptCode: sql`excluded."deptCode"`, deptName: sql`excluded."deptName"`, phone: sql`excluded.phone`, nonsapUserId: sql`excluded."nonsapUserId"`, isAbsent: sql`excluded."isAbsent"`, isDeletedOnNonSap: sql`excluded."isDeletedOnNonSap"`, isActive: sql`excluded."isActive"`, isRegularEmployee: sql`excluded."isRegularEmployee"`, updatedAt: sql`now()`, }, }); debugSuccess(`[UPSERT] users upserted=${mappedUsers.length} using key=nonsapUserId`); } else { debugWarn('[UPSERT] No users mapped for upsert (missing name/email or invalid USR_ID)'); } // 휴직 사용자도 API에서 수신하므로, 기존 사용자와의 비교를 통한 휴직 처리 로직은 더 이상 필요하지 않음 return { fetched: Array.isArray(data) ? data.length : 0, staged: Array.isArray(data) ? data.length : 0, upserted: mappedUsers.length, skippedDueToMissingRequiredFields: (Array.isArray(data) ? data.length : 0) - mappedUsers.length, ranAt: now.toISOString(), }; } catch(error){ debugError('SHI-API 동기화 실패', error); console.error("SHI-API 를 통한 유저 동기화 프로세스 간 실패 발생: ", error); throw error; } };