diff options
Diffstat (limited to 'lib/tech-vendors')
| -rw-r--r-- | lib/tech-vendors/service.ts | 198 | ||||
| -rw-r--r-- | lib/tech-vendors/table/import-button.tsx | 76 |
2 files changed, 235 insertions, 39 deletions
diff --git a/lib/tech-vendors/service.ts b/lib/tech-vendors/service.ts index f5380889..e8dcb5dc 100644 --- a/lib/tech-vendors/service.ts +++ b/lib/tech-vendors/service.ts @@ -1423,29 +1423,138 @@ export async function importTechVendorsFromExcel( }); continue; } + // 1. 이메일로 기존 벤더 중복 체크 - const existingVendor = await tx.query.techVendors.findFirst({ + let existingVendor = await tx.query.techVendors.findFirst({ where: eq(techVendors.email, vendor.email), - columns: { id: true, vendorName: true, email: true } + columns: { id: true, vendorName: true, vendorCode: true, email: true } }); + // 2. 이메일이 중복되지 않은 경우 벤더 코드나 이름으로 추가 확인 + if (!existingVendor && vendor.vendorCode) { + existingVendor = await tx.query.techVendors.findFirst({ + where: eq(techVendors.vendorCode, vendor.vendorCode), + columns: { id: true, vendorName: true, vendorCode: true, email: true } + }); + } + + // 3. 벤더 코드도 일치하지 않는 경우 벤더 이름으로 확인 + if (!existingVendor) { + existingVendor = await tx.query.techVendors.findFirst({ + where: eq(techVendors.vendorName, vendor.vendorName), + columns: { id: true, vendorName: true, vendorCode: true, email: true } + }); + } + + // 4. 일치하는 벤더가 있는 경우 처리 if (existingVendor) { - console.log("이미 존재하는 벤더 스킵:", vendor.vendorName, vendor.email); + console.log("기존 벤더에 담당자 추가:", existingVendor.vendorName, vendor.email); + + // 기존 벤더의 벤더 타입 업데이트 (새로운 타입 추가) + const existingVendorFull = await tx.query.techVendors.findFirst({ + where: eq(techVendors.id, existingVendor.id), + columns: { id: true, techVendorType: true } + }); + + if (existingVendorFull) { + const existingTypes = existingVendorFull.techVendorType ? existingVendorFull.techVendorType.split(',').map(t => t.trim()) : []; + const newType = vendor.techVendorType.trim(); + + // 새로운 타입이 기존에 없는 경우에만 추가 + if (!existingTypes.includes(newType)) { + const updatedTypes = [...existingTypes, newType]; + const updatedTypeString = updatedTypes.join(', '); + + await tx.update(techVendors) + .set({ techVendorType: updatedTypeString }) + .where(eq(techVendors.id, existingVendor.id)); + + console.log(`벤더 타입 업데이트: ${existingVendorFull.techVendorType} -> ${updatedTypeString}`); + } + } + + // 담당자 정보를 기존 벤더에 추가 + let contactName = vendor.vendorName; + let contactEmail = vendor.email; + + // vendor.contacts가 있고, contactName이 있으면 contactName 사용 + if (vendor.contacts && vendor.contacts.length > 0 && vendor.contacts[0].contactName) { + contactName = vendor.contacts[0].contactName; + // 만약 contactEmail이 있으면 그걸 사용, 없으면 vendor.email 사용 + if (vendor.contacts[0].contactEmail) { + contactEmail = vendor.contacts[0].contactEmail; + } + } + + // 담당자 이메일 중복 체크 + const existingContact = await tx.query.techVendorContacts.findFirst({ + where: and( + eq(techVendorContacts.vendorId, existingVendor.id), + eq(techVendorContacts.contactEmail, contactEmail) + ), + columns: { id: true, contactEmail: true } + }); + + if (existingContact) { + console.log("담당자 이메일 중복:", contactEmail); + errors.push({ + vendorName: vendor.vendorName, + email: vendor.email, + error: `담당자 이메일 '${contactEmail}'이(가) 이미 등록되어 있습니다` + }); + } else { + // 담당자 생성 + await tx.insert(techVendorContacts).values({ + vendorId: existingVendor.id, + contactName: contactName, + contactPosition: null, + contactEmail: contactEmail, + contactPhone: null, + contactCountry: null, + isPrimary: false, + }); + console.log("담당자 추가 성공:", contactName, contactEmail); + } + + // 기존 벤더에 담당자 추가했으므로 벤더 생성은 스킵하고 유저 생성으로 넘어감 skippedVendors.push({ vendorName: vendor.vendorName, email: vendor.email, - reason: `이미 등록된 이메일입니다 (기존 업체: ${existingVendor.vendorName})` + reason: `기존 벤더에 담당자 추가됨 (기존 업체: ${existingVendor.vendorName})` }); - continue; + + // 유저 생성 (기존 벤더의 담당자로 추가된 경우) + if (contactEmail) { + console.log("유저 생성 시도:", contactEmail); + + // 이미 존재하는 유저인지 확인 + const existingUser = await tx.query.users.findFirst({ + where: eq(users.email, contactEmail), + columns: { id: true } + }); + + if (!existingUser) { + // 유저가 존재하지 않는 경우 생성 + await tx.insert(users).values({ + name: contactName, + email: contactEmail, + techCompanyId: existingVendor.id, + domain: "partners", + }); + console.log("유저 생성 성공"); + } else { + // 이미 존재하는 유저라면 techCompanyId 업데이트 + await tx.update(users) + .set({ techCompanyId: existingVendor.id }) + .where(eq(users.id, existingUser.id)); + console.log("이미 존재하는 유저, techCompanyId 업데이트:", existingUser.id); + } + } + + continue; // 벤더 생성 부분으로 넘어가지 않음 } // 2. 벤더 생성 - console.log("벤더 생성 시도:", { - vendorName: vendor.vendorName, - email: vendor.email, - techVendorType: vendor.techVendorType - }); - const [newVendor] = await tx.insert(techVendors).values({ vendorName: vendor.vendorName, vendorCode: vendor.vendorCode || null, @@ -1486,30 +1595,21 @@ export async function importTechVendorsFromExcel( }); console.log("담당자 생성 성공:", contact.contactName, contact.contactEmail); } - - // // 벤더 이메일을 주 담당자의 이메일로 업데이트 - // const primaryContact = vendor.contacts.find(c => c.isPrimary) || vendor.contacts[0]; - // if (primaryContact && primaryContact.contactEmail !== vendor.email) { - // await tx.update(techVendors) - // .set({ email: primaryContact.contactEmail }) - // .where(eq(techVendors.id, newVendor.id)); - // console.log("벤더 이메일 업데이트:", primaryContact.contactEmail); - // } } - // else { - // // 담당자 정보가 없는 경우 벤더 정보로 기본 담당자 생성 - // console.log("기본 담당자 생성"); - // await tx.insert(techVendorContacts).values({ - // vendorId: newVendor.id, - // contactName: vendor.representativeName || vendor.vendorName || "기본 담당자", - // contactPosition: null, - // contactEmail: vendor.email, - // contactPhone: vendor.representativePhone || vendor.phone || null, - // contactCountry: vendor.country || null, - // isPrimary: true, - // }); - // console.log("기본 담당자 생성 성공:", vendor.email); - // } + else { + // 담당자 정보가 없는 경우 벤더 정보로 기본 담당자 생성 + console.log("기본 담당자 생성"); + await tx.insert(techVendorContacts).values({ + vendorId: newVendor.id, + contactName: vendor.representativeName || vendor.vendorName || "기본 담당자", + contactPosition: null, + contactEmail: vendor.email, + contactPhone: vendor.representativePhone || vendor.phone || null, + contactCountry: vendor.country || null, + isPrimary: true, + }); + console.log("기본 담당자 생성 성공:", vendor.email); + } // 3. 유저 생성 (이메일이 있는 경우) if (vendor.email) { @@ -3038,11 +3138,37 @@ export async function importPossibleItemsFromExcel( continue } - const vendor = await findVendorByEmail(row.vendorEmail.trim()) + let vendor = await findVendorByEmail(row.vendorEmail.trim()) + + // 2. 벤더 테이블에서 찾을 수 없는 경우, 담당자 테이블에서 찾기 + if (!vendor) { + console.log(`벤더 테이블에서 찾을 수 없음, 담당자 테이블에서 검색: ${row.vendorEmail}`) + + // 담당자 테이블에서 해당 이메일로 검색 + const contact = await db.query.techVendorContacts.findFirst({ + where: eq(techVendorContacts.contactEmail, row.vendorEmail.trim()), + columns: { vendorId: true, contactEmail: true } + }) + + if (contact) { + console.log(`담당자 테이블에서 찾음, 벤더 ID: ${contact.vendorId}`) + + // 해당 벤더 정보 가져오기 + vendor = await db.query.techVendors.findFirst({ + where: eq(techVendors.id, contact.vendorId), + columns: { id: true, vendorName: true, email: true } + }) + + if (vendor) { + console.log(`담당자를 통해 벤더 찾음: ${vendor.vendorName}`) + } + } + } + if (!vendor) { result.failedRows.push({ row: rowNumber, - error: `벤더 이메일 '${row.vendorEmail}'을(를) 찾을 수 없습니다.`, + error: `벤더 이메일 '${row.vendorEmail}'을(를) 찾을 수 없습니다. (벤더 테이블과 담당자 테이블 모두에서 검색 실패)`, vendorEmail: row.vendorEmail, itemCode: row.itemCode, itemType: row.itemType as "조선" | "해양TOP" | "해양HULL", diff --git a/lib/tech-vendors/table/import-button.tsx b/lib/tech-vendors/table/import-button.tsx index 1d3bf242..b268d29d 100644 --- a/lib/tech-vendors/table/import-button.tsx +++ b/lib/tech-vendors/table/import-button.tsx @@ -101,8 +101,14 @@ export function ImportTechVendorButton({ onSuccess }: ImportTechVendorButtonProp // 헤더를 기반으로 인덱스 매핑 생성
const headerMapping: Record<string, number> = {};
headerValues.forEach((value, index) => {
- if (typeof value === 'string') {
- headerMapping[value] = index;
+ // 리치텍스트를 일반 텍스트로 변환
+ const cleanValue = typeof value === 'string' ? value :
+ value && typeof value === 'object' && 'richText' in value ?
+ value.richText?.map((rt: any) => rt.text || '').join('') || '' :
+ String(value || '');
+
+ if (cleanValue && cleanValue.trim()) {
+ headerMapping[cleanValue] = index;
}
});
@@ -156,7 +162,19 @@ export function ImportTechVendorButton({ onSuccess }: ImportTechVendorButtonProp // 헤더 매핑에 따라 데이터 추출
Object.entries(headerMapping).forEach(([header, index]) => {
- rowData[header] = values[index] || "";
+ const rawValue = values[index];
+
+ // 리치텍스트를 일반 텍스트로 변환
+ let cleanValue = "";
+ if (typeof rawValue === 'string') {
+ cleanValue = rawValue;
+ } else if (rawValue && typeof rawValue === 'object' && 'richText' in rawValue) {
+ cleanValue = rawValue.richText?.map((rt: any) => rt.text || '').join('') || '';
+ } else if (rawValue !== null && rawValue !== undefined) {
+ cleanValue = String(rawValue);
+ }
+
+ rowData[header] = cleanValue;
});
// 빈 행이 아닌 경우만 추가
@@ -271,6 +289,58 @@ export function ImportTechVendorButton({ onSuccess }: ImportTechVendorButtonProp toast.error(result.error || "벤더 가져오기에 실패했습니다.");
}
+ // 에러가 있으면 에러 엑셀 다운로드 (성공/실패 상관없이)
+ if (result.details?.errors && result.details.errors.length > 0) {
+ try {
+ // 에러 데이터를 Excel로 변환
+ const errorWorkbook = new ExcelJS.Workbook();
+ const errorWorksheet = errorWorkbook.addWorksheet("오류내역");
+
+ // 헤더 추가
+ errorWorksheet.columns = [
+ { header: "업체명", key: "vendorName", width: 25 },
+ { header: "이메일", key: "email", width: 30 },
+ { header: "오류내용", key: "error", width: 80, style: { alignment: { wrapText: true }, font: { color: { argb: "FFFF0000" } } } },
+ ];
+
+ // 헤더 스타일 설정
+ const headerRow = errorWorksheet.getRow(1);
+ headerRow.font = { bold: true };
+ headerRow.fill = {
+ type: "pattern",
+ pattern: "solid",
+ fgColor: { argb: "FFFFCCCC" },
+ };
+
+ // 오류 데이터 추가
+ result.details.errors.forEach(errorItem => {
+ errorWorksheet.addRow({
+ vendorName: errorItem.vendorName || "N/A",
+ email: errorItem.email || "N/A",
+ error: errorItem.error || "알 수 없는 오류",
+ });
+ });
+
+ const buffer = await errorWorkbook.xlsx.writeBuffer();
+ const blob = new Blob([buffer], {
+ type: "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",
+ });
+ const url = window.URL.createObjectURL(blob);
+ const link = document.createElement("a");
+ link.href = url;
+ link.download = "벤더_import_에러.xlsx";
+ document.body.appendChild(link);
+ link.click();
+ document.body.removeChild(link);
+ window.URL.revokeObjectURL(url);
+
+ toast.info("에러 내역 파일이 다운로드되었습니다.");
+ } catch (excelError) {
+ console.error("에러 엑셀 생성 실패:", excelError);
+ toast.error("에러 엑셀 생성에 실패했습니다.");
+ }
+ }
+
// 상태 초기화 및 다이얼로그 닫기
setFile(null);
setOpen(false);
|
