summaryrefslogtreecommitdiff
path: root/lib/rfq-last/service.ts
diff options
context:
space:
mode:
Diffstat (limited to 'lib/rfq-last/service.ts')
-rw-r--r--lib/rfq-last/service.ts188
1 files changed, 183 insertions, 5 deletions
diff --git a/lib/rfq-last/service.ts b/lib/rfq-last/service.ts
index 09d707d7..78d2479a 100644
--- a/lib/rfq-last/service.ts
+++ b/lib/rfq-last/service.ts
@@ -3,7 +3,7 @@
import { revalidatePath, unstable_cache, unstable_noStore } from "next/cache";
import db from "@/db/db";
-import { avlVendorInfo, paymentTerms, incoterms, rfqLastVendorQuotationItems, rfqLastVendorAttachments, rfqLastVendorResponses, RfqsLastView, rfqLastAttachmentRevisions, rfqLastAttachments, rfqsLast, rfqsLastView, users, rfqPrItems, prItemsLastView, vendors, rfqLastDetails, rfqLastVendorResponseHistory, rfqLastDetailsView, vendorContacts, projects, basicContract, basicContractTemplates, rfqLastTbeSessions, rfqLastTbeDocumentReviews, templateDetailView } from "@/db/schema";
+import { avlVendorInfo, paymentTerms, incoterms, rfqLastVendorQuotationItems, rfqLastVendorAttachments, rfqLastVendorResponses, RfqsLastView, rfqLastAttachmentRevisions, rfqLastAttachments, rfqsLast, rfqsLastView, users, rfqPrItems, prItemsLastView, vendors, rfqLastDetails, rfqLastVendorResponseHistory, rfqLastDetailsView, vendorContacts, projects, basicContract, basicContractTemplates, rfqLastTbeSessions, rfqLastTbeDocumentReviews, templateDetailView, RfqStatus } from "@/db/schema";
import { sql, and, desc, asc, like, ilike, or, eq, SQL, count, gte, lte, isNotNull, ne, inArray } from "drizzle-orm";
import { filterColumns } from "@/lib/filter-columns";
import { GetRfqLastAttachmentsSchema, GetRfqsSchema } from "./validations";
@@ -1527,6 +1527,9 @@ export async function getRfqVendorResponses(rfqId: number) {
submittedBy: rfqLastVendorResponses.submittedBy,
submittedByName: users.name,
+ isDocumentConfirmed: rfqLastVendorResponses.isDocumentConfirmed,
+
+
// 금액 정보
totalAmount: rfqLastVendorResponses.totalAmount,
currency: rfqLastVendorResponses.currency,
@@ -1709,6 +1712,7 @@ export async function getRfqVendorResponses(rfqId: number) {
responseVersion: response.responseVersion,
isLatest: response.isLatest,
status: response.status,
+ isDocumentConfirmed: response.isDocumentConfirmed,
// 벤더 정보
vendor: {
@@ -2980,7 +2984,7 @@ export async function sendRfqToVendors({
// 6. RFQ 상태 업데이트
if (results.length > 0) {
- await updateRfqStatus(rfqId, currentUser.id);
+ await updateRfqStatus(rfqId, Number(currentUser.id));
}
return {
@@ -4812,13 +4816,24 @@ export async function updateShortList(
.update(rfqLastTbeSessions)
.set({
status: "준비중",
- updatedBy: session.user.id,
+ updatedBy: Number(session.user.id),
updatedAt: new Date()
})
.where(eq(rfqLastTbeSessions.id, existingSession[0].id));
}
})
);
+
+ // 2-3. RFQ 상태를 "Short List 확정"으로 업데이트
+ await tx
+ .update(rfqsLast)
+ .set({
+ status: "Short List 확정" as RfqStatus,
+ updatedBy: Number(session.user.id),
+ updatedAt: new Date()
+ })
+ .where(eq(rfqsLast.id, rfqId));
+
} else {
// shortList가 false인 경우, 해당 벤더들의 활성 TBE 세션을 취소 상태로 변경
await Promise.all(
@@ -4839,21 +4854,60 @@ export async function updateShortList(
)
)
);
+
+ // shortList를 해제하는 경우의 상태 처리
+ // 모든 벤더의 shortList가 false인지 확인
+ const remainingShortlisted = await tx
+ .select()
+ .from(rfqLastDetails)
+ .where(
+ and(
+ eq(rfqLastDetails.rfqsLastId, rfqId),
+ eq(rfqLastDetails.isLatest, true),
+ eq(rfqLastDetails.shortList, true)
+ )
+ )
+ .limit(1);
+
+ // 남은 shortList 벤더가 없으면 RFQ 상태를 이전 상태로 되돌림
+ // if (remainingShortlisted.length === 0) {
+ // await tx
+ // .update(rfqsLast)
+ // .set({
+ // status: "견적 접수" as RfqStatus, // 또는 적절한 이전 상태
+ // updatedBy: Number(session.user.id),
+ // updatedAt: new Date()
+ // })
+ // .where(eq(rfqsLast.id, rfqId));
+ // }
}
return {
success: true,
updatedCount: updatedDetails.length,
vendorIds,
- tbeSessionsUpdated: shortListStatus
+ tbeSessionsUpdated: shortListStatus,
+ rfqStatusUpdated: true
};
}
+ // 벤더가 없는 경우 (모든 shortList를 false로만 설정)
+ // RFQ 상태를 이전 상태로 되돌림
+ await tx
+ .update(rfqsLast)
+ .set({
+ status: "견적 접수" as RfqStatus, // 또는 적절한 이전 상태
+ updatedBy: Number(session.user.id),
+ updatedAt: new Date()
+ })
+ .where(eq(rfqsLast.id, rfqId));
+
return {
success: true,
updatedCount: 0,
vendorIds: [],
- tbeSessionsUpdated: false
+ tbeSessionsUpdated: false,
+ rfqStatusUpdated: true
};
});
@@ -5209,3 +5263,127 @@ export async function addAvlVendorsToRfq({
};
}
}
+
+
+
+interface ConfirmVendorDocumentsResult {
+ success: boolean;
+ message: string;
+ updatedCount?: number;
+}
+
+/**
+ * 특정 벤더의 모든 문서를 확정 처리
+ * @param rfqId RFQ ID
+ * @param vendorId 벤더 ID
+ * @returns 처리 결과
+ */
+export async function confirmVendorDocuments(
+ rfqId: number,
+ vendorId: number
+): Promise<ConfirmVendorDocumentsResult> {
+ try {
+ // 데이터 유효성 검증
+ if (!rfqId || !vendorId) {
+ return {
+ success: false,
+ message: "RFQ ID와 벤더 ID가 필요합니다.",
+ };
+ }
+
+ // 트랜잭션으로 두 테이블 동시 업데이트
+ const result = await db.transaction(async (tx) => {
+ // 1. rfqLastVendorResponses 테이블 업데이트
+ const vendorResponseResult = await tx
+ .update(rfqLastVendorResponses)
+ .set({
+ isDocumentConfirmed: true,
+ updatedAt: new Date(),
+ })
+ .where(
+ and(
+ eq(rfqLastVendorResponses.rfqsLastId, rfqId),
+ eq(rfqLastVendorResponses.vendorId, vendorId)
+ )
+ )
+ .returning({ id: rfqLastVendorResponses.id });
+
+ // 업데이트된 레코드 수 확인
+ const updatedCount = vendorResponseResult.length;
+
+ if (updatedCount === 0) {
+ throw new Error("해당 조건에 맞는 문서를 찾을 수 없습니다.");
+ }
+
+ // 2. rfqsLast 테이블 status 업데이트
+ const rfqUpdateResult = await tx
+ .update(rfqsLast)
+ .set({
+ status: "견적요청문서 확정" as RfqStatus,
+ updatedAt: new Date(),
+ })
+ .where(eq(rfqsLast.id, rfqId))
+ .returning({ id: rfqsLast.id });
+
+ if (rfqUpdateResult.length === 0) {
+ throw new Error("RFQ 상태 업데이트에 실패했습니다.");
+ }
+
+ return updatedCount;
+ });
+
+ // 캐시 무효화 (필요한 경우)
+ revalidatePath(`/rfq-last/${rfqId}`);
+
+ return {
+ success: true,
+ message: `문서가 확정되었습니다.`,
+ updatedCount: result,
+ };
+ } catch (error) {
+ console.log("문서 확정 중 오류 발생:", error);
+
+ return {
+ success: false,
+ message: error instanceof Error
+ ? `문서 확정 실패: ${error.message}`
+ : "문서 확정 중 알 수 없는 오류가 발생했습니다.",
+ };
+ }
+}
+
+/**
+ * 특정 벤더의 문서 확정 상태 조회
+ * @param rfqId RFQ ID
+ * @param vendorId 벤더 ID
+ * @returns 확정 상태
+ */
+export async function getVendorDocumentConfirmStatus(
+ rfqId: number,
+ vendorId: number
+): Promise<{ isConfirmed: boolean; count: number }> {
+ try {
+ const results = await db
+ .select({
+ isDocumentConfirmed: rfqLastVendorResponses.isDocumentConfirmed,
+ })
+ .from(rfqLastVendorResponses)
+ .where(
+ and(
+ eq(rfqLastVendorResponses.rfqsLastId, rfqId),
+ eq(rfqLastVendorResponses.vendorId, vendorId)
+ )
+ );
+
+ const confirmedCount = results.filter(r => r.isDocumentConfirmed).length;
+ const totalCount = results.length;
+
+ return {
+ isConfirmed: totalCount > 0 && confirmedCount === totalCount,
+ count: totalCount,
+ };
+ } catch (error) {
+ console.error("문서 확정 상태 조회 중 오류:", error);
+ return { isConfirmed: false, count: 0 };
+ }
+} \ No newline at end of file