diff options
| author | dujinkim <dujin.kim@dtsolution.co.kr> | 2025-09-26 09:57:24 +0000 |
|---|---|---|
| committer | dujinkim <dujin.kim@dtsolution.co.kr> | 2025-09-26 09:57:24 +0000 |
| commit | 8b23b471638a155fd1bfa3a8c853b26d9315b272 (patch) | |
| tree | 47353e9dd342011cb2f1dcd24b09661707a8421b /lib/tags | |
| parent | d62368d2b68d73da895977e60a18f9b1286b0545 (diff) | |
(대표님) 권한관리, 문서업로드, rfq첨부, SWP문서룰 등
(최겸) 입찰
Diffstat (limited to 'lib/tags')
| -rw-r--r-- | lib/tags/service.ts | 348 |
1 files changed, 180 insertions, 168 deletions
diff --git a/lib/tags/service.ts b/lib/tags/service.ts index cef20209..028cde42 100644 --- a/lib/tags/service.ts +++ b/lib/tags/service.ts @@ -393,69 +393,89 @@ export async function createTagInForm( formCode: string, packageCode: string ) { + // 1. 초기 검증 if (!selectedPackageId) { - return { error: "No selectedPackageId provided" } + console.error("[CREATE TAG] No selectedPackageId provided"); + return { + success: false, + error: "No selectedPackageId provided" + }; } - // Validate formData - const validated = createTagSchema.safeParse(formData) + // 2. FormData 검증 + const validated = createTagSchema.safeParse(formData); if (!validated.success) { - return { error: validated.error.flatten().formErrors.join(", ") } + const errorMsg = validated.error.flatten().formErrors.join(", "); + console.error("[CREATE TAG] Validation failed:", errorMsg); + return { + success: false, + error: errorMsg + }; } - // React 서버 액션에서 매 요청마다 실행 - unstable_noStore() + // 3. 캐시 무효화 설정 + unstable_noStore(); try { - // 하나의 트랜잭션에서 모든 작업 수행 + // 4. 트랜잭션 시작 return await db.transaction(async (tx) => { - // 1) 선택된 contractItem의 contractId 가져오기 + // 5. Contract Item 정보 조회 const contractItemResult = await tx .select({ contractId: contractItems.contractId, - projectId: contracts.projectId, // projectId 추가 - vendorId: contracts.vendorId // projectId 추가 + projectId: contracts.projectId, + vendorId: contracts.vendorId }) .from(contractItems) - .innerJoin(contracts, eq(contractItems.contractId, contracts.id)) // contracts 테이블 조인 + .innerJoin(contracts, eq(contractItems.contractId, contracts.id)) .where(eq(contractItems.id, selectedPackageId)) - .limit(1) + .limit(1); if (contractItemResult.length === 0) { - return { error: "Contract item not found" } + console.error("[CREATE TAG] Contract item not found"); + return { + success: false, + error: "Contract item not found" + }; } - const contractId = contractItemResult[0].contractId - const projectId = contractItemResult[0].projectId - const vendorId = contractItemResult[0].vendorId + const { contractId, projectId, vendorId } = contractItemResult[0]; - const vendor = await db.query.vendors.findFirst({ + // 6. Vendor 정보 조회 + const vendor = await tx.query.vendors.findFirst({ where: eq(vendors.id, vendorId) }); - + if (!vendor) { - return { error: "선택한 벤더를 찾을 수 없습니다." }; + console.error("[CREATE TAG] Vendor not found"); + return { + success: false, + error: "선택한 벤더를 찾을 수 없습니다." + }; } - // 2) 해당 계약 내에서 같은 tagNo를 가진 태그가 있는지 확인 + // 7. 중복 태그 확인 const duplicateCheck = await tx .select({ count: sql<number>`count(*)` }) .from(tags) .innerJoin(contractItems, eq(tags.contractItemId, contractItems.id)) + .innerJoin(contracts, eq(contractItems.contractId, contracts.id)) .where( and( - eq(contractItems.contractId, contractId), + eq(contracts.projectId, projectId), eq(tags.tagNo, validated.data.tagNo) ) - ) + ); if (duplicateCheck[0].count > 0) { + console.error(`[CREATE TAG] Duplicate tag number: ${validated.data.tagNo}`); return { + success: false, error: `태그 번호 "${validated.data.tagNo}"는 이미 이 계약 내에 존재합니다.`, - } + }; } - // 3) 먼저 기존 form 찾기 + // 8. Form 조회 let form = await tx.query.forms.findFirst({ where: and( eq(forms.formCode, formCode), @@ -463,191 +483,183 @@ export async function createTagInForm( ) }); - // 4) form이 없으면 formMappings를 통해 생성 + // 9. Form이 없으면 생성 if (!form) { - console.log(`[CREATE TAG IN FORM] Form ${formCode} not found, attempting to create...`); + console.log(`[CREATE TAG] Form ${formCode} not found, attempting to create...`); - // 태그 타입에 따른 폼 정보 가져오기 + // Form Mappings 조회 const allFormMappings = await getFormMappingsByTagType( validated.data.tagType, projectId, validated.data.class - ) - - - - - // ep가 "IMEP"인 것만 필터링 - const formMappings = allFormMappings?.filter(mapping => mapping.ep === "IMEP") || [] + ); - // 현재 formCode와 일치하는 매핑 찾기 + // IMEP 폼만 필터링 + const formMappings = allFormMappings?.filter(mapping => mapping.ep === "IMEP") || []; 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)); + if (!targetFormMapping) { + console.error(`[CREATE TAG] No IMEP form mapping found for formCode: ${formCode}`); return { + success: false, 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 생성 + 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() + }; - // 기존 form이 있지만 im이 false인 경우 true로 업데이트 + console.log(`[CREATE TAG] Successfully created form:`, insertResult[0]); + } else { + // 기존 form의 im 상태 업데이트 if (form.im !== true) { await tx .update(forms) .set({ im: true }) - .where(eq(forms.id, form.id)) + .where(eq(forms.id, form.id)); - console.log(`[CREATE TAG IN FORM] Form ${form.id} updated with im: true`) + console.log(`[CREATE TAG] Form ${form.id} updated with im: true`); } } - if (form?.id) { - // 🆕 16진수 24자리 태그 고유 식별자 생성 - const generatedTagIdx = generateTagIdx(); - console.log(`[CREATE TAG IN FORM] Generated tagIdx: ${generatedTagIdx}`); + // 10. Form이 있는 경우에만 진행 + if (!form?.id) { + console.error("[CREATE TAG] Failed to create or find form"); + return { + success: false, + error: "Failed to create or find form" + }; + } - // 5) 새 Tag 생성 (tagIdx 추가) - const [newTag] = await insertTag(tx, { - contractItemId: selectedPackageId, - formId: form.id, - tagIdx: generatedTagIdx, // 🆕 생성된 16진수 24자리 추가 - tagNo: validated.data.tagNo, - class: validated.data.class, - tagType: validated.data.tagType, - description: validated.data.description ?? null, - }) + // 11. Tag Index 생성 + const generatedTagIdx = generateTagIdx(); + console.log(`[CREATE TAG] Generated tagIdx: ${generatedTagIdx}`); - // 6) 기존 formEntry 가져오기 - const entry = await tx.query.formEntries.findFirst({ - where: and( - eq(formEntries.formCode, formCode), - eq(formEntries.contractItemId, selectedPackageId), - ) - }); + // 12. 새 Tag 생성 + const [newTag] = await insertTag(tx, { + contractItemId: selectedPackageId, + formId: form.id, + tagIdx: generatedTagIdx, + tagNo: validated.data.tagNo, + class: validated.data.class, + tagType: validated.data.tagType, + description: validated.data.description ?? null, + }); - if (entry && entry.id) { - // 7) 기존 데이터 가져오기 (배열인지 확인) - TAG_IDX 타입 추가 - let existingData: Array<{ - TAG_IDX?: string; // 🆕 TAG_IDX 필드 추가 - TAG_NO: string; - TAG_DESC?: string; - status?: string; - [key: string]: any; // 다른 필드들도 포함 - }> = []; - - if (Array.isArray(entry.data)) { - existingData = entry.data; - } + // 13. Tag Class 조회 + const tagClass = await tx.query.tagClasses.findFirst({ + where: and( + eq(tagClasses.projectId, projectId), + eq(tagClasses.label, validated.data.class) + ) + }); - console.log(`[CREATE TAG IN FORM] Existing data count: ${existingData.length}`); + if (!tagClass) { + console.warn("[CREATE TAG] Tag class not found, using default"); + } - const tagClass = await db.query.tagClasses.findFirst({ - where: and(eq(tagClasses.projectId, projectId),eq(tagClasses.label, validated.data.class)) - }); + // 14. FormEntry 처리 + const entry = await tx.query.formEntries.findFirst({ + where: and( + eq(formEntries.formCode, formCode), + eq(formEntries.contractItemId, selectedPackageId), + ) + }); - // 8) 새로운 태그를 기존 데이터에 추가 (TAG_IDX 포함) - const newTagData = { - TAG_IDX: generatedTagIdx, // 🆕 같은 16진수 24자리 값 사용 - TAG_NO: validated.data.tagNo, - TAG_DESC: validated.data.description ?? null, - CLS_ID: tagClass.code, - VNDRCD: vendor.vendorCode, - VNDRNM_1: vendor.vendorName, - CM3003: packageCode, - ME5074: packageCode, + // 15. 새로운 태그 데이터 준비 + const newTagData = { + TAG_IDX: generatedTagIdx, + TAG_NO: validated.data.tagNo, + TAG_DESC: validated.data.description ?? null, + CLS_ID: tagClass?.code || validated.data.class, // tagClass가 없을 경우 대비 + VNDRCD: vendor.vendorCode, + VNDRNM_1: vendor.vendorName, + CM3003: packageCode, + ME5074: packageCode, + status: "New" // 수동으로 생성된 태그임을 표시 + }; - status: "New" // 수동으로 생성된 태그임을 표시 - }; + if (entry?.id) { + // 16. 기존 FormEntry 업데이트 + let existingData: Array<any> = []; + if (Array.isArray(entry.data)) { + existingData = entry.data; + } - const updatedData = [...existingData, newTagData]; + console.log(`[CREATE TAG] Existing data count: ${existingData.length}`); - console.log(`[CREATE TAG IN FORM] Updated data count: ${updatedData.length}`); - console.log(`[CREATE TAG IN FORM] Added tag: ${validated.data.tagNo} with tagIdx: ${generatedTagIdx}, status: 수동 생성`); + const updatedData = [...existingData, newTagData]; - // 9) formEntries 업데이트 - await tx - .update(formEntries) - .set({ - data: updatedData, - updatedAt: new Date() // 업데이트 시간도 갱신 - }) - .where(eq(formEntries.id, entry.id)); - } else { - // 10) formEntry가 없는 경우 새로 생성 (TAG_IDX 포함) - console.log(`[CREATE TAG IN FORM] No existing formEntry found, creating new one`); - - const newEntryData = [{ - TAG_IDX: generatedTagIdx, // 🆕 같은 16진수 24자리 값 사용 - TAG_NO: validated.data.tagNo, - TAG_DESC: validated.data.description ?? null, - status: "New" // 수동으로 생성된 태그임을 표시 - }]; + await tx + .update(formEntries) + .set({ + data: updatedData, + updatedAt: new Date() + }) + .where(eq(formEntries.id, entry.id)); - await tx.insert(formEntries).values({ - formCode: formCode, - contractItemId: selectedPackageId, - data: newEntryData, - createdAt: new Date(), - updatedAt: new Date(), - }); - } + console.log(`[CREATE TAG] Updated formEntry with new tag`); + } else { + // 17. 새 FormEntry 생성 + console.log(`[CREATE TAG] Creating new formEntry`); + + await tx.insert(formEntries).values({ + formCode: formCode, + contractItemId: selectedPackageId, + data: [newTagData], + createdAt: new Date(), + updatedAt: new Date(), + }); + + console.log(`[CREATE TAG] Created new formEntry`); + } + + // 18. 캐시 무효화 + revalidateTag(`tags-${selectedPackageId}`); + revalidateTag(`forms-${selectedPackageId}`); + revalidateTag(`form-data-${formCode}-${selectedPackageId}`); + revalidateTag("tags"); - // 12) 성공 시 반환 + console.log(`[CREATE TAG] Successfully created tag: ${validated.data.tagNo} with tagIdx: ${generatedTagIdx}`); + + // 19. 성공 응답 return { success: true, data: { formId: form.id, tagNo: validated.data.tagNo, - tagIdx: generatedTagIdx, // 🆕 생성된 tagIdx도 반환 - formCreated: !form // form이 새로 생성되었는지 여부 + tagIdx: generatedTagIdx, + formCreated: !form } - } - - console.log(`[CREATE TAG IN FORM] Successfully created tag: ${validated.data.tagNo} with tagIdx: ${generatedTagIdx}`) - } else { - return { error: "Failed to create or find form" }; - } - - // 11) 캐시 무효화 (React 서버 액션에서 캐싱 사용 시) - revalidateTag(`tags-${selectedPackageId}`) - revalidateTag(`forms-${selectedPackageId}`) - revalidateTag(`form-data-${formCode}-${selectedPackageId}`) // 폼 데이터 캐시도 무효화 - revalidateTag("tags") - - - }) + }; + }); } catch (err: any) { - console.log("createTag in Form error:", err) - console.error("createTag in Form error:", err) - return { error: getErrorMessage(err) } + // 20. 에러 처리 + console.error("[CREATE TAG] Transaction error:", err); + const errorMessage = getErrorMessage(err); + + return { + success: false, + error: errorMessage + }; } } |
