diff options
Diffstat (limited to 'lib/vendors/blacklist-check.ts')
| -rw-r--r-- | lib/vendors/blacklist-check.ts | 170 |
1 files changed, 170 insertions, 0 deletions
diff --git a/lib/vendors/blacklist-check.ts b/lib/vendors/blacklist-check.ts new file mode 100644 index 00000000..c72bb1bf --- /dev/null +++ b/lib/vendors/blacklist-check.ts @@ -0,0 +1,170 @@ +"use server"; + +import crypto from 'crypto'; +import { oracleKnex } from '@/lib/oracle-db/db'; + +/** + * 문자열을 SHA-1으로 해시하여 대문자로 반환 + */ +function sha1Hash(text: string): string { + return crypto + .createHash('sha1') + .update(text, 'utf8') + .digest('hex') + .toUpperCase(); +} + +/** + * 생년월일에서 숫자만 추출하고 YYMMDD 형식(6자리)로 변환 + * 예: "1999-01-01" -> "990101" + * 예: "99-01-01" -> "990101" + * 예: "1988-02-06" -> "880206" + */ +function processBirthDate(birthDate: string | null | undefined): string { + if (!birthDate) { + throw new Error('생년월일 정보가 없습니다.'); + } + + // 숫자만 추출 + const numbersOnly = birthDate.replace(/\D/g, ''); + + if (numbersOnly.length === 6) { + // 6자리(YYMMDD)면 그대로 사용 + return numbersOnly; + } else if (numbersOnly.length === 8) { + // 8자리(YYYYMMDD)면 앞 2자리 제거하여 YYMMDD로 변환 + return numbersOnly.substring(2); + } else { + throw new Error(`생년월일 형식이 올바르지 않습니다. (입력값: ${birthDate}, 숫자 길이: ${numbersOnly.length})`); + } +} + +/** + * 블랙리스트 검사 결과 타입 + */ +export interface BlacklistCheckResult { + isBlacklisted: boolean; + message: string; + count?: number; +} + +/** + * 단일 벤더의 블랙리스트 여부 확인 + */ +export async function checkVendorBlacklist( + representativeName: string | null | undefined, + representativeBirth: string | null | undefined +): Promise<BlacklistCheckResult> { + try { + // 필수 정보 검증 + if (!representativeName || !representativeBirth) { + return { + isBlacklisted: false, + message: '대표자 이름 또는 생년월일 정보가 없어 블랙리스트 검사를 진행할 수 없습니다.', + }; + } + + // 이름 해시값 생성 + const nameHash = sha1Hash(representativeName); + + // 생년월일 처리 (YYMMDD 6자리로 변환) + let birthProcessed: string; + try { + birthProcessed = processBirthDate(representativeBirth); + } catch (error) { + return { + isBlacklisted: false, + message: error instanceof Error ? error.message : '생년월일 처리 중 오류가 발생했습니다.', + }; + } + + // YYMMDD 전체를 해시 계산 + // 예: "880206" → SHA1("880206") + const birthHash = sha1Hash(birthProcessed); + + console.log('🔍 [블랙리스트 검사]', { + input: representativeBirth, + processed: birthProcessed, + nameHash, + birthHash + }); + + // Oracle DB 조회 + const result = await oracleKnex + .select(oracleKnex.raw('COUNT(*) as cnt')) + .from('SHIVND.AMG0070') + .where('NM', nameHash) + .andWhere('BRDT', birthHash) + .first() as unknown as { cnt?: number; CNT?: number } | undefined; + + const count = Number(result?.cnt || result?.CNT || 0); + const isBlacklisted = count > 0; + + if (isBlacklisted) { + return { + isBlacklisted: true, + message: '블랙리스트에 등록된 대표자입니다. 가입 승인을 진행할 수 없습니다.', + count, + }; + } + + return { + isBlacklisted: false, + message: '블랙리스트 검사 통과', + count: 0, + }; + } catch (error) { + console.error('블랙리스트 검사 오류:', error); + throw new Error('블랙리스트 검사 중 오류가 발생했습니다.'); + } +} + +/** + * 여러 벤더의 블랙리스트 여부 일괄 확인 + */ +export async function checkVendorsBlacklist( + vendors: Array<{ + id: string; + name: string; + representativeName: string | null; + representativeBirth: string | null; + }> +): Promise<{ + success: boolean; + blacklistedVendors: Array<{ id: string; name: string; message: string }>; + checkedCount: number; +}> { + const blacklistedVendors: Array<{ id: string; name: string; message: string }> = []; + + for (const vendor of vendors) { + try { + const result = await checkVendorBlacklist( + vendor.representativeName, + vendor.representativeBirth + ); + + if (result.isBlacklisted) { + blacklistedVendors.push({ + id: vendor.id, + name: vendor.name, + message: result.message, + }); + } + } catch (error) { + // 개별 벤더 검사 실패 시에도 계속 진행 + console.error(`벤더 ${vendor.name} 블랙리스트 검사 실패:`, error); + blacklistedVendors.push({ + id: vendor.id, + name: vendor.name, + message: '블랙리스트 검사 중 오류가 발생했습니다.', + }); + } + } + + return { + success: blacklistedVendors.length === 0, + blacklistedVendors, + checkedCount: vendors.length, + }; +} + |
