diff options
| author | dujinkim <dujin.kim@dtsolution.co.kr> | 2025-09-25 03:28:27 +0000 |
|---|---|---|
| committer | dujinkim <dujin.kim@dtsolution.co.kr> | 2025-09-25 03:28:27 +0000 |
| commit | 4c2d4c235bd80368e31cae9c375e9a585f6a6844 (patch) | |
| tree | 7fd1847e1e30ef2052281453bfb7a1c45ac6627a /lib/itb/service.ts | |
| parent | f69e125f1a0b47bbc22e2784208bf829bcdd24f8 (diff) | |
(대표님) archiver 추가, 데이터룸구현
Diffstat (limited to 'lib/itb/service.ts')
| -rw-r--r-- | lib/itb/service.ts | 417 |
1 files changed, 210 insertions, 207 deletions
diff --git a/lib/itb/service.ts b/lib/itb/service.ts index f649bdf5..181285cc 100644 --- a/lib/itb/service.ts +++ b/lib/itb/service.ts @@ -3,7 +3,7 @@ import db from "@/db/db"; import { purchaseRequestsView, purchaseRequests, purchaseRequestAttachments, rfqsLast, rfqLastAttachments, rfqLastAttachmentRevisions, rfqPrItems, users } from "@/db/schema"; -import { eq, and, desc, ilike, or, sql, asc, inArray ,like} from "drizzle-orm"; +import { eq, and, desc, ilike, or, sql, asc, inArray, like } from "drizzle-orm"; import { revalidatePath, revalidateTag } from "next/cache"; import { getServerSession } from 'next-auth/next' import { authOptions } from '@/app/api/auth/[...nextauth]/route' @@ -293,7 +293,7 @@ export async function approvePurchaseRequestAndCreateRfq( .where(eq(purchaseRequestAttachments.requestId, requestId)); - const rfqCode = await generateItbRfqCode(purchasePicId); + const rfqCode = await generateItbRfqCode(purchasePicId); const [rfq] = await tx.insert(rfqsLast).values({ rfqCode, @@ -547,10 +547,10 @@ export async function getPurchaseRequestAttachments(requestId: number) { } } catch (error) { console.error("Get attachments error:", error) - return { + return { success: false, error: "첨부파일 조회 중 오류가 발생했습니다.", - data: [] + data: [] } } } @@ -558,223 +558,226 @@ export async function getPurchaseRequestAttachments(requestId: number) { export async function generateItbRfqCode(purchasePicId?: number): Promise<string> { try { - let userCode = "???"; - - // purchasePicId가 있으면 users 테이블에서 userCode 조회 - if (purchasePicId) { - const [user] = await db - .select({ userCode: users.userCode }) - .from(users) - .where(eq(users.id, purchasePicId)) - .limit(1); - - if (user?.userCode) { - userCode = user.userCode; + let userCode = "???"; + + // purchasePicId가 있으면 users 테이블에서 userCode 조회 + if (purchasePicId) { + const [user] = await db + .select({ userCode: users.userCode }) + .from(users) + .where(eq(users.id, purchasePicId)) + .limit(1); + + if (user?.userCode) { + userCode = user.userCode; + } } - } - - // 동일한 userCode로 시작하는 마지막 RFQ 조회 - const lastRfq = await db - .select({ rfqCode: rfqsLast.rfqCode }) - .from(rfqsLast) - .where(like(rfqsLast.rfqCode, `I${userCode}%`)) - .orderBy(desc(rfqsLast.createdAt)) - .limit(1); - - let nextNumber = 1; - - if (lastRfq.length > 0 && lastRfq[0].rfqCode) { - const rfqCode = lastRfq[0].rfqCode; - const serialNumber = rfqCode.slice(-5); // 마지막 5자리 - - if (/^\d{5}$/.test(serialNumber)) { - nextNumber = parseInt(serialNumber) + 1; + + // 동일한 userCode로 시작하는 마지막 RFQ 조회 + const lastRfq = await db + .select({ rfqCode: rfqsLast.rfqCode }) + .from(rfqsLast) + .where(like(rfqsLast.rfqCode, `I${userCode}%`)) + .orderBy(desc(rfqsLast.createdAt)) + .limit(1); + + let nextNumber = 1; + + if (lastRfq.length > 0 && lastRfq[0].rfqCode) { + const rfqCode = lastRfq[0].rfqCode; + const serialNumber = rfqCode.slice(-5); // 마지막 5자리 + + if (/^\d{5}$/.test(serialNumber)) { + nextNumber = parseInt(serialNumber) + 1; + } } - } - - const paddedNumber = String(nextNumber).padStart(5, "0"); - - return `I${userCode}${paddedNumber}`; + + const paddedNumber = String(nextNumber).padStart(5, "0"); + + return `I${userCode}${paddedNumber}`; } catch (error) { - console.error("Error generating ITB RFQ code:", error); - const fallback = Date.now().toString().slice(-5); - return `I???${fallback}`; + console.error("Error generating ITB RFQ code:", error); + const fallback = Date.now().toString().slice(-5); + return `I???${fallback}`; } - } - +} + - // lib/purchase-requests/service.ts에 추가 +// lib/purchase-requests/service.ts에 추가 // 여러 구매 요청 승인 및 RFQ 생성 export async function approvePurchaseRequestsAndCreateRfqs( requestIds: number[], purchasePicId?: number - ) { +) { try { - const session = await getServerSession(authOptions) - if (!session?.user?.id) throw new Error("Unauthorized"); - const userId = Number(session.user.id) - - const results = [] - - for (const requestId of requestIds) { - try { - const result = await db.transaction(async (tx) => { - // 구매 요청 조회 - const [request] = await tx - .select() - .from(purchaseRequests) - .where(eq(purchaseRequests.id, requestId)) - - if (!request) { - throw new Error(`구매 요청 ${requestId}를 찾을 수 없습니다.`) - } - - if (request.status === "RFQ생성완료") { - return { skipped: true, requestId, message: "이미 RFQ가 생성되었습니다." } - } - - const attachments = await tx - .select() - .from(purchaseRequestAttachments) - .where(eq(purchaseRequestAttachments.requestId, requestId)) - - const rfqCode = await generateItbRfqCode(purchasePicId) - - // 마감일 기본값 설정 (입력값 없으면 생성일 + 7일) - const defaultDueDate = getDefaultDueDate(); - - const [rfq] = await tx - .insert(rfqsLast) - .values({ - rfqCode, - projectId: request.projectId, - itemCode: request.items?.[0]?.itemCode, - itemName: request.items?.[0]?.itemName, - packageNo: request.packageNo, - packageName: request.packageName, - EngPicName: request.engPicName, - pic: purchasePicId || null, - status: "RFQ 생성", - dueDate: defaultDueDate, // 마감일 기본값 설정 - projectCompany: request.projectCompany, - projectSite: request.projectSite, - smCode: request.smCode, - createdBy: userId, - updatedBy: userId, - }) - .returning() - - // 첨부파일 이관 - for (const [index, attachment] of attachments.entries()) { - const [rfqAttachment] = await tx - .insert(rfqLastAttachments) - .values({ - attachmentType: "설계", - serialNo: `ENG-${String(index + 1).padStart(3, "0")}`, - rfqId: rfq.id, - description: - attachment.description || - `설계문서 - ${attachment.originalFileName}`, - currentRevision: "Rev.0", - createdBy: userId, - }) - .returning() - - const [revision] = await tx - .insert(rfqLastAttachmentRevisions) - .values({ - attachmentId: rfqAttachment.id, - revisionNo: "Rev.0", - revisionComment: "구매 요청에서 이관된 설계 문서", - isLatest: true, - fileName: attachment.fileName, - originalFileName: attachment.originalFileName, - filePath: attachment.filePath, - fileSize: attachment.fileSize, - fileType: attachment.fileType, - createdBy: userId, + const session = await getServerSession(authOptions) + if (!session?.user?.id) throw new Error("Unauthorized"); + const userId = Number(session.user.id) + + const results = [] + + for (const requestId of requestIds) { + try { + const result = await db.transaction(async (tx) => { + // 구매 요청 조회 + const [request] = await tx + .select() + .from(purchaseRequests) + .where(eq(purchaseRequests.id, requestId)) + + if (!request) { + throw new Error(`구매 요청 ${requestId}를 찾을 수 없습니다.`) + } + + if (request.status === "RFQ생성완료") { + return { skipped: true, requestId, message: "이미 RFQ가 생성되었습니다." } + } + + const attachments = await tx + .select() + .from(purchaseRequestAttachments) + .where(eq(purchaseRequestAttachments.requestId, requestId)) + + const rfqCode = await generateItbRfqCode(purchasePicId) + + const defaultDueDate = (() => { + const d = new Date(); + d.setDate(d.getDate() + 15); + return d; + })(); + + + const [rfq] = await tx + .insert(rfqsLast) + .values({ + rfqCode, + projectId: request.projectId, + itemCode: request.items?.[0]?.itemCode, + itemName: request.items?.[0]?.itemName, + packageNo: request.packageNo, + packageName: request.packageName, + EngPicName: request.engPicName, + pic: purchasePicId || null, + status: "RFQ 생성", + dueDate: defaultDueDate, // 마감일 기본값 설정 + projectCompany: request.projectCompany, + projectSite: request.projectSite, + smCode: request.smCode, + createdBy: userId, + updatedBy: userId, + }) + .returning() + + // 첨부파일 이관 + for (const [index, attachment] of attachments.entries()) { + const [rfqAttachment] = await tx + .insert(rfqLastAttachments) + .values({ + attachmentType: "설계", + serialNo: `ENG-${String(index + 1).padStart(3, "0")}`, + rfqId: rfq.id, + description: + attachment.description || + `설계문서 - ${attachment.originalFileName}`, + currentRevision: "Rev.0", + createdBy: userId, + }) + .returning() + + const [revision] = await tx + .insert(rfqLastAttachmentRevisions) + .values({ + attachmentId: rfqAttachment.id, + revisionNo: "Rev.0", + revisionComment: "구매 요청에서 이관된 설계 문서", + isLatest: true, + fileName: attachment.fileName, + originalFileName: attachment.originalFileName, + filePath: attachment.filePath, + fileSize: attachment.fileSize, + fileType: attachment.fileType, + createdBy: userId, + }) + .returning() + + await tx + .update(rfqLastAttachments) + .set({ latestRevisionId: revision.id }) + .where(eq(rfqLastAttachments.id, rfqAttachment.id)) + } + + // 품목 이관 + if (request.items && request.items.length > 0) { + console.log("🚀 품목 이관 시작:", { + requestId, + itemsCount: request.items.length, + items: request.items + }); + + const prItemsData = request.items.map((item, index) => ({ + rfqsLastId: rfq.id, + rfqItem: `${index + 1}`.padStart(3, '0'), + prItem: `${index + 1}`.padStart(3, '0'), + prNo: rfqCode, + materialCategory: request.majorItemMaterialCategory, + materialCode: item.itemCode, + materialDescription: item.itemName, + quantity: item.quantity, + uom: item.unit, + majorYn: index === 0, + remark: item.remarks || null, + })); + + console.log("🔍 삽입할 데이터:", prItemsData); + + const insertedItems = await tx.insert(rfqPrItems).values(prItemsData).returning(); + console.log("✅ 품목 이관 완료:", insertedItems); + } else { + console.log("❌ 품목이 없음:", { + requestId, + hasItems: !!request.items, + itemsLength: request.items?.length || 0 + }); + } + + // 구매 요청 상태 업데이트 + await tx + .update(purchaseRequests) + .set({ + status: "RFQ생성완료", + rfqId: rfq.id, + rfqCode: rfq.rfqCode, + rfqCreatedAt: new Date(), + purchasePicId, + updatedBy: userId, + updatedAt: new Date(), + }) + .where(eq(purchaseRequests.id, requestId)) + + return { success: true, rfq, requestId } }) - .returning() - - await tx - .update(rfqLastAttachments) - .set({ latestRevisionId: revision.id }) - .where(eq(rfqLastAttachments.id, rfqAttachment.id)) - } - - // 품목 이관 - if (request.items && request.items.length > 0) { - console.log("🚀 품목 이관 시작:", { - requestId, - itemsCount: request.items.length, - items: request.items - }); - - const prItemsData = request.items.map((item, index) => ({ - rfqsLastId: rfq.id, - rfqItem: `${index + 1}`.padStart(3, '0'), - prItem: `${index + 1}`.padStart(3, '0'), - prNo: rfqCode, - materialCategory:request.majorItemMaterialCategory, - materialCode: item.itemCode, - materialDescription: item.itemName, - quantity: item.quantity, - uom: item.unit, - majorYn: index === 0, - remark: item.remarks || null, - })); - - console.log("🔍 삽입할 데이터:", prItemsData); - - const insertedItems = await tx.insert(rfqPrItems).values(prItemsData).returning(); - console.log("✅ 품목 이관 완료:", insertedItems); - } else { - console.log("❌ 품목이 없음:", { + + results.push(result) + } catch (err: any) { + console.error(`구매 요청 ${requestId} 처리 중 오류:`, err) + results.push({ + success: false, requestId, - hasItems: !!request.items, - itemsLength: request.items?.length || 0 - }); + error: err.message || "알 수 없는 오류 발생", + }) } - - // 구매 요청 상태 업데이트 - await tx - .update(purchaseRequests) - .set({ - status: "RFQ생성완료", - rfqId: rfq.id, - rfqCode: rfq.rfqCode, - rfqCreatedAt: new Date(), - purchasePicId, - updatedBy: userId, - updatedAt: new Date(), - }) - .where(eq(purchaseRequests.id, requestId)) - - return { success: true, rfq, requestId } - }) - - results.push(result) - } catch (err: any) { - console.error(`구매 요청 ${requestId} 처리 중 오류:`, err) - results.push({ - success: false, - requestId, - error: err.message || "알 수 없는 오류 발생", - }) } - } - - // 캐시 무효화 - revalidateTag("purchase-requests") - revalidateTag( "purchase-request-stats") - - revalidateTag("rfqs") - - return results + + // 캐시 무효화 + revalidateTag("purchase-requests") + revalidateTag("purchase-request-stats") + + revalidateTag("rfqs") + + return results } catch (err: any) { - console.error("approvePurchaseRequestsAndCreateRfqs 실행 오류:", err) - throw new Error(err.message || "구매 요청 처리 중 오류가 발생했습니다.") + console.error("approvePurchaseRequestsAndCreateRfqs 실행 오류:", err) + throw new Error(err.message || "구매 요청 처리 중 오류가 발생했습니다.") } - } -
\ No newline at end of file +} |
