summaryrefslogtreecommitdiff
path: root/lib/tech-vendors
diff options
context:
space:
mode:
Diffstat (limited to 'lib/tech-vendors')
-rw-r--r--lib/tech-vendors/service.ts198
-rw-r--r--lib/tech-vendors/table/import-button.tsx76
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);