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
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
|
'use client';
import { useState, useEffect, useCallback } from 'react';
import { getCreditInfo } from '@/lib/oracle-db/nonsap/services/creditService';
// 신용평가사 옵션
const creditServices = [
{ code: 'I', name: '이크레더블' },
{ code: 'K', name: '한국기업데이터' },
{ code: 'N', name: '나이스디앤비' },
{ code: 'E', name: 'NICE신용평가사' }
];
interface CreditData {
// 기본 정보
RESNO: string;
EENTNM: string;
OPEDT: string;
REPR_NM: string;
TYSCALE: string;
RELCMP: string;
ADR: string;
LISTYN: string;
GOODSNM: string;
TELNO: string;
FAXNO: string;
FSTRDRT: string;
// 매출순위
MO_1: string;
MO_4: string;
MO_2: string;
MO_5: string;
MO_3: string;
MO_6: string;
// 매입순위
MI_1: string;
MI_4: string;
MI_2: string;
MI_5: string;
MI_3: string;
MI_6: string;
// 지분관계
GIBUN_RL_1: string;
LSH_STK_RATE1: string;
GIBUN_RL_2: string;
LSH_STK_RATE2: string;
GIBUN_RL_3: string;
LSH_STK_RATE3: string;
// 기타 정보
HAPGYE: string;
NOTICE: string;
NOTICE_DT: string;
HPGBNCR_TY: string;
FCLOSDT: string;
LASTGRD: string;
DECISION: string;
FRISKRV: string;
EXPIRE_GB: string;
FWATCHD: string;
SUVDT: string;
ESETDTT: string;
// 재무년월
bs_dt0: string;
bs_dt1: string;
bs_dt2: string;
// 재무현황
bs59_0: string; // 총자산
bs59_1: string;
bs59_2: string;
bs91_0: string; // 부채총계
bs91_1: string;
bs91_2: string;
bs113_0: string; // 자본총계
bs113_1: string;
bs113_2: string;
pl01_0: string; // 매출액
pl01_1: string;
pl01_2: string;
pl27_0: string; // 영업이익
pl27_1: string;
pl27_2: string;
pl71_0: string; // 당기순이익
pl71_1: string;
pl71_2: string;
// 재무비율
TR0053: string; // 부채비율
TR0052: string;
TR0051: string;
TR0513: string; // 차입금의존도
TR0512: string;
TR0511: string;
TR0523: string; // 영업이익율
TR0522: string;
TR0521: string;
TR0103: string; // 매출순이익율
TR0102: string;
TR0101: string;
TR0223: string; // 매출액증가율
TR0222: string;
TR0221: string;
TR0013: string; // 유동비율
TR0012: string;
TR0011: string;
}
interface CreditServiceResult {
code: string;
name: string;
data: CreditData | null;
dataCount: number;
success: boolean;
error: string | null;
}
export function useCreditIntegration(vendorId: string) {
const [loading, setLoading] = useState(false);
const [error, setError] = useState<string | null>(null);
const [creditResults, setCreditResults] = useState<CreditServiceResult[]>([]);
const [selectedCreditService, setSelectedCreditService] = useState<string>('auto');
const [bestResult, setBestResult] = useState<CreditServiceResult | null>(null);
// 데이터 개수를 계산하는 함수
const calculateDataCount = (data: CreditData | null): number => {
if (!data) return 0;
let count = 0;
const fieldsToCheck = [
// 재무현황 필드들
'bs59_0', 'bs59_1', 'bs59_2', // 총자산
'bs91_0', 'bs91_1', 'bs91_2', // 부채총계
'bs113_0', 'bs113_1', 'bs113_2', // 자본총계
'pl01_0', 'pl01_1', 'pl01_2', // 매출액
'pl27_0', 'pl27_1', 'pl27_2', // 영업이익
'pl71_0', 'pl71_1', 'pl71_2', // 당기순이익
// 재무비율 필드들
'TR0053', 'TR0052', 'TR0051', // 부채비율
'TR0513', 'TR0512', 'TR0511', // 차입금의존도
'TR0523', 'TR0522', 'TR0521', // 영업이익율
'TR0103', 'TR0102', 'TR0101', // 순이익율
'TR0223', 'TR0222', 'TR0221', // 매출액증가율
'TR0013', 'TR0012', 'TR0011', // 유동비율
];
fieldsToCheck.forEach(field => {
const value = data[field as keyof CreditData];
if (value && value.toString().trim() !== '' && value.toString().trim() !== '0') {
count++;
}
});
return count;
};
// 모든 신용평가사 데이터를 병렬로 조회
const loadAllCreditData = useCallback(async () => {
if (!vendorId) return;
setLoading(true);
setError(null);
try {
const promises = creditServices.map(async (service) => {
try {
const result = await getCreditInfo(vendorId, service.code);
const data = result && result.length > 0 ? result[0] : null;
const dataCount = calculateDataCount(data);
return {
code: service.code,
name: service.name,
data,
dataCount,
success: true,
error: null
};
} catch (err) {
console.error(`Error loading credit data for ${service.name}:`, err);
return {
code: service.code,
name: service.name,
data: null,
dataCount: 0,
success: false,
error: `${service.name} 데이터 조회 실패`
};
}
});
const results = await Promise.all(promises);
setCreditResults(results);
// 모든 신용평가사 조회가 실패했는지 확인
const allFailed = results.every(result => !result.success);
if (allFailed) {
const failedServices = results.filter(r => !r.success).map(r => r.name).join(', ');
setError(`모든 신용평가사 데이터 조회에 실패했습니다: ${failedServices}`);
setBestResult(null);
return;
}
// 부분적으로 실패한 경우에도 성공한 것들로 진행
const successfulResults = results.filter(result => result.success);
// 데이터 개수가 가장 많은 결과 찾기 (성공한 것들 중에서)
const best = successfulResults.reduce((prev, current) => {
return current.dataCount > prev.dataCount ? current : prev;
}, successfulResults[0]);
setBestResult(best && best.dataCount > 0 ? best : null);
// 성공했지만 모든 데이터가 비어있는 경우
if (successfulResults.length > 0 && successfulResults.every(r => r.dataCount === 0)) {
setError(null); // 오류는 아니므로 에러 메시지 지우기
}
} catch (err) {
setError('신용평가 데이터를 불러오는 중 예상치 못한 오류가 발생했습니다.');
console.error(err);
setBestResult(null);
} finally {
setLoading(false);
}
}, [vendorId]);
// 신용평가사 선택 변경 핸들러
const handleCreditServiceChange = (code: string) => {
setSelectedCreditService(code);
};
// 현재 선택된 결과 반환
const getCurrentResult = (): CreditServiceResult | null => {
if (selectedCreditService === 'auto') {
return bestResult;
}
return creditResults.find(r => r.code === selectedCreditService) || null;
};
// Credit 데이터를 Basic 페이지 형식으로 변환
const transformCreditToSalesData = (creditData: CreditData | null) => {
if (!creditData) return null;
// 날짜 변환 함수 (20.12.31 -> 20201231)
const convertDateToYYYYMMDD = (dateStr: string): string => {
if (!dateStr) return '';
const parts = dateStr.split('.');
if (parts.length >= 3) {
let year = parseInt(parts[0]);
const month = parts[1].padStart(2, '0');
const day = parts[2].padStart(2, '0');
// 2자리 연도를 4자리로 변환
if (year >= 0 && year <= 30) {
year = 2000 + year;
} else if (year >= 70 && year <= 99) {
year = 1900 + year;
}
return `${year}${month}${day}`;
}
return '';
};
// 숫자 값 정리 함수
const cleanNumber = (value: string): string => {
if (!value) return '0';
return value.replace(/,/g, '').trim();
};
const salesInfo: { [year: string]: { totalSales: string; totalDebt: string; totalEquity: string; operatingProfit: string; netIncome: string; } } = {};
const calculatedMetrics: { [year: string]: { debtRatio: number; borrowingDependency: number; operatingMargin: number; netMargin: number; salesGrowth: number; currentRatio: number; } } = {};
// 3개년 데이터 변환
for (let i = 0; i < 3; i++) {
const yearKey = convertDateToYYYYMMDD(creditData[`bs_dt${i}` as keyof CreditData] as string);
if (!yearKey) continue;
// 매출정보 변환
salesInfo[yearKey] = {
totalSales: cleanNumber(creditData[`pl01_${i}` as keyof CreditData] as string),
totalDebt: cleanNumber(creditData[`bs91_${i}` as keyof CreditData] as string),
totalEquity: cleanNumber(creditData[`bs113_${i}` as keyof CreditData] as string),
operatingProfit: cleanNumber(creditData[`pl27_${i}` as keyof CreditData] as string),
netIncome: cleanNumber(creditData[`pl71_${i}` as keyof CreditData] as string),
};
// 계산된 지표 변환 (i=0은 최신년도, i=2는 가장 오래된 년도)
calculatedMetrics[yearKey] = {
debtRatio: parseFloat(creditData[`TR005${3-i}` as keyof CreditData] as string) || 0, // TR0053, TR0052, TR0051
borrowingDependency: parseFloat(creditData[`TR051${3-i}` as keyof CreditData] as string) || 0, // TR0513, TR0512, TR0511
operatingMargin: parseFloat(creditData[`TR052${3-i}` as keyof CreditData] as string) || 0, // TR0523, TR0522, TR0521
netMargin: parseFloat(creditData[`TR010${3-i}` as keyof CreditData] as string) || 0, // TR0103, TR0102, TR0101
salesGrowth: parseFloat(creditData[`TR022${3-i}` as keyof CreditData] as string) || 0, // TR0223, TR0222, TR0221
currentRatio: parseFloat(creditData[`TR001${3-i}` as keyof CreditData] as string) || 0, // TR0013, TR0012, TR0011
};
}
return { salesInfo, calculatedMetrics };
};
// 초기 데이터 로드
useEffect(() => {
if (vendorId) {
loadAllCreditData();
}
}, [vendorId, loadAllCreditData]);
return {
loading,
error,
creditResults,
selectedCreditService,
bestResult,
getCurrentResult,
handleCreditServiceChange,
transformCreditToSalesData,
creditServices: [...creditServices, { code: 'auto', name: '자동선택 (최적)' }],
reload: loadAllCreditData
};
}
|