diff options
| author | dujinkim <dujin.kim@dtsolution.co.kr> | 2025-06-01 13:52:21 +0000 |
|---|---|---|
| committer | dujinkim <dujin.kim@dtsolution.co.kr> | 2025-06-01 13:52:21 +0000 |
| commit | bac0228d21b7195065e9cddcc327ae33659c7bcc (patch) | |
| tree | 8f3016ae4533c8706d0c00a605d9b1d41968c2bc /lib/tags | |
| parent | 2fdce8d7a57c792bba0ac36fa554dca9c9cc31e3 (diff) | |
(대표님) 20250601까지 작업사항
Diffstat (limited to 'lib/tags')
| -rw-r--r-- | lib/tags/form-mapping-service.ts | 5 | ||||
| -rw-r--r-- | lib/tags/service.ts | 411 |
2 files changed, 375 insertions, 41 deletions
diff --git a/lib/tags/form-mapping-service.ts b/lib/tags/form-mapping-service.ts index 19b3ab14..3e86e9d9 100644 --- a/lib/tags/form-mapping-service.ts +++ b/lib/tags/form-mapping-service.ts @@ -8,6 +8,8 @@ import { eq, and } from "drizzle-orm" export interface FormMapping { formCode: string; formName: string; + ep: string; + remark: string; } /** @@ -29,6 +31,8 @@ export async function getFormMappingsByTagType( .select({ formCode: tagTypeClassFormMappings.formCode, formName: tagTypeClassFormMappings.formName, + ep: tagTypeClassFormMappings.ep, + remark: tagTypeClassFormMappings.remark }) .from(tagTypeClassFormMappings) .where(and( @@ -49,6 +53,7 @@ export async function getFormMappingsByTagType( .select({ formCode: tagTypeClassFormMappings.formCode, formName: tagTypeClassFormMappings.formName, + ep: tagTypeClassFormMappings.ep }) .from(tagTypeClassFormMappings) .where(and( diff --git a/lib/tags/service.ts b/lib/tags/service.ts index 6a34d208..187aba39 100644 --- a/lib/tags/service.ts +++ b/lib/tags/service.ts @@ -145,11 +145,15 @@ export async function createTag( } // 3) 태그 타입에 따른 폼 정보 가져오기 - const formMappings = await getFormMappingsByTagType( + const allFormMappings = await getFormMappingsByTagType( validated.data.tagType, projectId, // projectId 전달 validated.data.class ) + + // ep가 "IMEP"인 것만 필터링 + const formMappings = allFormMappings?.filter(mapping => mapping.ep === "IMEP") || [] + // 폼 매핑이 없으면 로그만 남기고 진행 if (!formMappings || formMappings.length === 0) { @@ -171,7 +175,7 @@ export async function createTag( for (const formMapping of formMappings) { // 4-1) 이미 존재하는 폼인지 확인 const existingForm = await tx - .select({ id: forms.id, im: forms.im }) // im 필드 추가로 조회 + .select({ id: forms.id, im: forms.im, eng: forms.eng }) // eng 필드도 추가로 조회 .from(forms) .where( and( @@ -186,13 +190,29 @@ export async function createTag( // 이미 존재하면 해당 ID 사용 formId = existingForm[0].id + // 업데이트할 필드들 준비 + const updateValues: any = {}; + let shouldUpdate = false; + + // im 필드 체크 if (existingForm[0].im !== true) { + updateValues.im = true; + shouldUpdate = true; + } + + // eng 필드 체크 - remark에 "VD_"가 포함되어 있을 때만 + if (formMapping.remark && formMapping.remark.includes("VD_") && existingForm[0].eng !== true) { + updateValues.eng = true; + shouldUpdate = true; + } + + if (shouldUpdate) { await tx .update(forms) - .set({ im: true }) + .set(updateValues) .where(eq(forms.id, formId)) - console.log(`Form ${formId} updated with im: true`) + console.log(`Form ${formId} updated with:`, updateValues) } createdOrExistingForms.push({ @@ -203,14 +223,21 @@ export async function createTag( }) } else { // 존재하지 않으면 새로 생성 + const insertValues: any = { + contractItemId: selectedPackageId, + formCode: formMapping.formCode, + formName: formMapping.formName, + im: true, + }; + + // remark에 "VD_"가 포함되어 있을 때만 eng: true 설정 + if (formMapping.remark && formMapping.remark.includes("VD_")) { + insertValues.eng = true; + } + const insertResult = await tx .insert(forms) - .values({ - contractItemId: selectedPackageId, - formCode: formMapping.formCode, - formName: formMapping.formName, - im: true - }) + .values(insertValues) .returning({ id: forms.id, formCode: forms.formCode, formName: forms.formName }) console.log("insertResult:", insertResult) @@ -242,17 +269,93 @@ export async function createTag( console.log(`tags-${selectedPackageId}`, "create", newTag) - // 6) 캐시 무효화 (React 서버 액션에서 캐싱 사용 시) + // 6) 생성된 각 form에 대해 formEntries에 데이터 추가 + for (const form of createdOrExistingForms) { + try { + // 기존 formEntry 가져오기 + const existingEntry = await tx.query.formEntries.findFirst({ + where: and( + eq(formEntries.formCode, form.formCode), + eq(formEntries.contractItemId, selectedPackageId) + ) + }); + + // 새로운 태그 데이터 객체 생성 + const newTagData = { + TAG_NO: validated.data.tagNo, + TAG_DESC: validated.data.description ?? null, + status: "New" // 수동으로 생성된 태그임을 표시 + }; + + if (existingEntry && existingEntry.id) { + // 기존 formEntry가 있는 경우 + let existingData: Array<{ + TAG_NO: string; + TAG_DESC?: string; + status?: string; + [key: string]: any; + }> = []; + + if (Array.isArray(existingEntry.data)) { + existingData = existingEntry.data; + } + + // TAG_NO가 이미 존재하는지 확인 + const existingTagIndex = existingData.findIndex( + item => item.TAG_NO === validated.data.tagNo + ); + + if (existingTagIndex === -1) { + // TAG_NO가 없으면 새로 추가 + const updatedData = [...existingData, newTagData]; + + await tx + .update(formEntries) + .set({ + data: updatedData, + updatedAt: new Date() + }) + .where(eq(formEntries.id, existingEntry.id)); + + console.log(`[CREATE TAG] Added tag ${validated.data.tagNo} to existing formEntry for form ${form.formCode}`); + } else { + console.log(`[CREATE TAG] Tag ${validated.data.tagNo} already exists in formEntry for form ${form.formCode}`); + } + } else { + // formEntry가 없는 경우 새로 생성 + await tx.insert(formEntries).values({ + formCode: form.formCode, + contractItemId: selectedPackageId, + data: [newTagData], + createdAt: new Date(), + updatedAt: new Date(), + }); + + console.log(`[CREATE TAG] Created new formEntry with tag ${validated.data.tagNo} for form ${form.formCode}`); + } + } catch (formEntryError) { + console.error(`[CREATE TAG] Error updating formEntry for form ${form.formCode}:`, formEntryError); + // 개별 formEntry 에러는 로그만 남기고 전체 트랜잭션은 계속 진행 + } + } + + // 7) 캐시 무효화 (React 서버 액션에서 캐싱 사용 시) revalidateTag(`tags-${selectedPackageId}`) revalidateTag(`forms-${selectedPackageId}-ENG`) revalidateTag("tags") - // 7) 성공 시 반환 + // 생성된 각 form의 캐시도 무효화 + createdOrExistingForms.forEach(form => { + revalidateTag(`form-data-${form.formCode}-${selectedPackageId}`) + }) + + // 8) 성공 시 반환 return { success: true, data: { forms: createdOrExistingForms, primaryFormId, + tagNo: validated.data.tagNo }, } }) @@ -264,6 +367,7 @@ export async function createTag( } } + export async function createTagInForm( formData: CreateTagSchema, selectedPackageId: number | null, @@ -321,10 +425,77 @@ export async function createTagInForm( } } - const form = await db.query.forms.findFirst({ - where: eq(forms.formCode, formCode) + // 3) 먼저 기존 form 찾기 + let form = await tx.query.forms.findFirst({ + where: and( + eq(forms.formCode, formCode), + eq(forms.contractItemId, selectedPackageId) + ) }); + // 4) form이 없으면 formMappings를 통해 생성 + if (!form) { + console.log(`[CREATE TAG IN FORM] Form ${formCode} not found, attempting to create...`); + + // 태그 타입에 따른 폼 정보 가져오기 + const allFormMappings = await getFormMappingsByTagType( + validated.data.tagType, + projectId, + validated.data.class + ) + + // ep가 "IMEP"인 것만 필터링 + const formMappings = allFormMappings?.filter(mapping => mapping.ep === "IMEP") || [] + + // 현재 formCode와 일치하는 매핑 찾기 + const targetFormMapping = formMappings.find(mapping => mapping.formCode === formCode); + + if (targetFormMapping) { + console.log(`[CREATE TAG IN FORM] Found form mapping for ${formCode}, creating form...`); + + // form 생성 + const insertResult = await tx + .insert(forms) + .values({ + contractItemId: selectedPackageId, + formCode: targetFormMapping.formCode, + formName: targetFormMapping.formName, + im: true, + }) + .returning({ id: forms.id, formCode: forms.formCode, formName: forms.formName }) + + form = { + id: insertResult[0].id, + formCode: insertResult[0].formCode, + formName: insertResult[0].formName, + contractItemId: selectedPackageId, + im: true, + createdAt: new Date(), + updatedAt: new Date() + }; + + console.log(`[CREATE TAG IN FORM] Successfully created form:`, insertResult[0]); + } else { + console.log(`[CREATE TAG IN FORM] No IMEP form mapping found for formCode: ${formCode}`); + console.log(`[CREATE TAG IN FORM] Available IMEP mappings:`, formMappings.map(m => m.formCode)); + return { + error: `Form ${formCode} not found and no IMEP mapping available for tag type ${validated.data.tagType}` + }; + } + } else { + console.log(`[CREATE TAG IN FORM] Found existing form:`, form.id); + + // 기존 form이 있지만 im이 false인 경우 true로 업데이트 + if (form.im !== true) { + await tx + .update(forms) + .set({ im: true }) + .where(eq(forms.id, form.id)) + + console.log(`[CREATE TAG IN FORM] Form ${form.id} updated with im: true`) + } + } + if (form?.id) { // 5) 새 Tag 생성 (같은 트랜잭션 `tx` 사용) const [newTag] = await insertTag(tx, { @@ -336,48 +507,91 @@ export async function createTagInForm( description: validated.data.description ?? null, }) - let updatedData: Array<{ - TAG_NO: string; - TAG_DESC?: string; - }> = []; - - updatedData.push({ - TAG_NO: validated.data.tagNo, - TAG_DESC: validated.data.description ?? null, - }); - - const entry = await db.query.formEntries.findFirst({ + // 6) 기존 formEntry 가져오기 + const entry = await tx.query.formEntries.findFirst({ where: and( eq(formEntries.formCode, formCode), eq(formEntries.contractItemId, selectedPackageId), ) }); - if (entry && entry.id && updatedData.length > 0) { - await db + if (entry && entry.id) { + // 7) 기존 데이터 가져오기 (배열인지 확인) + let existingData: Array<{ + TAG_NO: string; + TAG_DESC?: string; + status?: string; + [key: string]: any; // 다른 필드들도 포함 + }> = []; + + if (Array.isArray(entry.data)) { + existingData = entry.data; + } + + console.log(`[CREATE TAG IN FORM] Existing data count: ${existingData.length}`); + + // 8) 새로운 태그를 기존 데이터에 추가 (status 필드 포함) + const newTagData = { + TAG_NO: validated.data.tagNo, + TAG_DESC: validated.data.description ?? null, + status: "New" // 수동으로 생성된 태그임을 표시 + }; + + const updatedData = [...existingData, newTagData]; + + console.log(`[CREATE TAG IN FORM] Updated data count: ${updatedData.length}`); + console.log(`[CREATE TAG IN FORM] Added tag: ${validated.data.tagNo} with status: 수동 생성`); + + // 9) formEntries 업데이트 + await tx .update(formEntries) - .set({ data: updatedData }) + .set({ + data: updatedData, + updatedAt: new Date() // 업데이트 시간도 갱신 + }) .where(eq(formEntries.id, entry.id)); + } else { + // 10) formEntry가 없는 경우 새로 생성 (status 필드 포함) + console.log(`[CREATE TAG IN FORM] No existing formEntry found, creating new one`); + + const newEntryData = [{ + TAG_NO: validated.data.tagNo, + TAG_DESC: validated.data.description ?? null, + status: "New" // 수동으로 생성된 태그임을 표시 + }]; + + await tx.insert(formEntries).values({ + formCode: formCode, + contractItemId: selectedPackageId, + data: newEntryData, + createdAt: new Date(), + updatedAt: new Date(), + }); } - console.log(`tags-${selectedPackageId}`, "create", newTag) - + console.log(`[CREATE TAG IN FORM] Successfully created tag: ${validated.data.tagNo}`) + } else { + return { error: "Failed to create or find form" }; } - // 6) 캐시 무효화 (React 서버 액션에서 캐싱 사용 시) + // 11) 캐시 무효화 (React 서버 액션에서 캐싱 사용 시) revalidateTag(`tags-${selectedPackageId}`) revalidateTag(`forms-${selectedPackageId}`) + revalidateTag(`form-data-${formCode}-${selectedPackageId}`) // 폼 데이터 캐시도 무효화 revalidateTag("tags") - // 7) 성공 시 반환 + // 12) 성공 시 반환 return { success: true, - data: null + data: { + formId: form.id, + tagNo: validated.data.tagNo, + formCreated: !form // form이 새로 생성되었는지 여부 + } } }) } catch (err: any) { console.log("createTag in Form error:", err) - console.error("createTag in Form error:", err) return { error: getErrorMessage(err) } } @@ -638,6 +852,13 @@ export async function bulkCreateTags( // 태그 유형별 폼 매핑 캐싱 (성능 최적화) const formMappingsCache = new Map(); + + // formEntries 업데이트를 위한 맵 (formCode -> 태그 데이터 배열) + const tagsByFormCode = new Map<string, Array<{ + TAG_NO: string; + TAG_DESC: string | null; + status: string; + }>>(); for (const tagData of tagsfromExcel) { // 캐시 키 생성 (tagType + class) @@ -648,12 +869,28 @@ export async function bulkCreateTags( if (formMappingsCache.has(cacheKey)) { formMappings = formMappingsCache.get(cacheKey); } else { + const tagTypeLabel = await tx + .select({ description: tagTypes.description }) + .from(tagTypes) + .where( + and( + eq(tagTypes.projectId, projectId), + eq(tagTypes.code, tagData.tagType), + ) + ) + .limit(1) + + const tagTypeLabelText = tagTypeLabel[0].description + // 각 태그 유형에 대한 폼 매핑 조회 (projectId 전달) - formMappings = await getFormMappingsByTagType( - tagData.tagType, + const allFormMappings = await getFormMappingsByTagType( + tagTypeLabelText, projectId, // projectId 전달 tagData.class ); + + // ep가 "IMEP"인 것만 필터링 + formMappings = allFormMappings?.filter(mapping => mapping.ep === "IMEP") || []; formMappingsCache.set(cacheKey, formMappings); } @@ -665,7 +902,7 @@ export async function bulkCreateTags( for (const formMapping of formMappings) { // 해당 폼이 이미 존재하는지 확인 const existingForm = await tx - .select({ id: forms.id }) + .select({ id: forms.id, im: forms.im }) .from(forms) .where( and( @@ -679,6 +916,15 @@ export async function bulkCreateTags( if (existingForm.length > 0) { // 이미 존재하면 해당 ID 사용 formId = existingForm[0].id; + + // im 필드 업데이트 (필요한 경우) + if (existingForm[0].im !== true) { + await tx + .update(forms) + .set({ im: true }) + .where(eq(forms.id, formId)); + } + createdOrExistingForms.push({ id: formId, formCode: formMapping.formCode, @@ -693,6 +939,7 @@ export async function bulkCreateTags( contractItemId: selectedPackageId, formCode: formMapping.formCode, formName: formMapping.formName, + im: true }) .returning({ id: forms.id, formCode: forms.formCode, formName: forms.formName }); @@ -709,10 +956,22 @@ export async function bulkCreateTags( if (primaryFormId === null) { primaryFormId = formId; } + + // formEntries 업데이트를 위한 데이터 수집 (tagsfromExcel의 원본 데이터 사용) + const newTagEntry = { + TAG_NO: tagData.tagNo, + TAG_DESC: tagData.description || null, + status: "New" // 벌크 생성도 수동 생성으로 분류 + }; + + if (!tagsByFormCode.has(formMapping.formCode)) { + tagsByFormCode.set(formMapping.formCode, []); + } + tagsByFormCode.get(formMapping.formCode)!.push(newTagEntry); } } else { console.log( - "No form mappings found for tag type:", + "No IMEP form mappings found for tag type:", tagData.tagType, "class:", tagData.class || "NONE", @@ -741,17 +1000,88 @@ export async function bulkCreateTags( }); } - // 4. 캐시 무효화 (한 번만) + // 4. formEntries 업데이트 처리 + for (const [formCode, newTagsData] of tagsByFormCode.entries()) { + try { + // 기존 formEntry 가져오기 + const existingEntry = await tx.query.formEntries.findFirst({ + where: and( + eq(formEntries.formCode, formCode), + eq(formEntries.contractItemId, selectedPackageId) + ) + }); + + if (existingEntry && existingEntry.id) { + // 기존 formEntry가 있는 경우 + let existingData: Array<{ + TAG_NO: string; + TAG_DESC?: string | null; + status?: string; + [key: string]: any; + }> = []; + + if (Array.isArray(existingEntry.data)) { + existingData = existingEntry.data; + } + + // 기존 TAG_NO들 추출 + const existingTagNos = new Set(existingData.map(item => item.TAG_NO)); + + // 중복되지 않은 새 태그들만 필터링 + const newUniqueTagsData = newTagsData.filter( + tagData => !existingTagNos.has(tagData.TAG_NO) + ); + + if (newUniqueTagsData.length > 0) { + const updatedData = [...existingData, ...newUniqueTagsData]; + + await tx + .update(formEntries) + .set({ + data: updatedData, + updatedAt: new Date() + }) + .where(eq(formEntries.id, existingEntry.id)); + + console.log(`[BULK CREATE] Added ${newUniqueTagsData.length} tags to existing formEntry for form ${formCode}`); + } else { + console.log(`[BULK CREATE] All tags already exist in formEntry for form ${formCode}`); + } + } else { + // formEntry가 없는 경우 새로 생성 + await tx.insert(formEntries).values({ + formCode: formCode, + contractItemId: selectedPackageId, + data: newTagsData, + createdAt: new Date(), + updatedAt: new Date(), + }); + + console.log(`[BULK CREATE] Created new formEntry with ${newTagsData.length} tags for form ${formCode}`); + } + } catch (formEntryError) { + console.error(`[BULK CREATE] Error updating formEntry for form ${formCode}:`, formEntryError); + // 개별 formEntry 에러는 로그만 남기고 전체 트랜잭션은 계속 진행 + } + } + + // 5. 캐시 무효화 (한 번만) revalidateTag(`tags-${selectedPackageId}`); revalidateTag(`forms-${selectedPackageId}`); revalidateTag("tags"); + // 업데이트된 모든 form의 캐시도 무효화 + for (const formCode of tagsByFormCode.keys()) { + revalidateTag(`form-data-${formCode}-${selectedPackageId}`); + } + return { success: true, data: { createdCount: createdTags.length, tags: createdTags, - formsInfo: allFormsInfo + formsInfo: allFormsInfo, + formEntriesUpdated: tagsByFormCode.size // 업데이트된 formEntry 수 } }; }); @@ -760,7 +1090,6 @@ export async function bulkCreateTags( return { error: getErrorMessage(err) || "Failed to create tags" }; } } - /** 복수 삭제 */ interface RemoveTagsInput { ids: number[]; |
