1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
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,
};
}
|