From 14f61e24947fb92dd71ec0a7196a6e815f8e66da Mon Sep 17 00:00:00 2001 From: dujinkim Date: Mon, 21 Jul 2025 07:54:26 +0000 Subject: (최겸)기술영업 RFQ 담당자 초대, 요구사항 반영 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- lib/contact-possible-items/service.ts | 190 ++++++++++++++++++++++++++++++++++ 1 file changed, 190 insertions(+) create mode 100644 lib/contact-possible-items/service.ts (limited to 'lib/contact-possible-items/service.ts') diff --git a/lib/contact-possible-items/service.ts b/lib/contact-possible-items/service.ts new file mode 100644 index 00000000..f4b89368 --- /dev/null +++ b/lib/contact-possible-items/service.ts @@ -0,0 +1,190 @@ +"use server" + +import db from "@/db/db" +import { techSalesContactPossibleItems } from "@/db/schema/techSales" +import { techVendors, techVendorContacts, techVendorPossibleItems } from "@/db/schema/techVendors" +import { eq, desc, ilike, count, or } from "drizzle-orm" +import { revalidatePath } from "next/cache" +import { unstable_noStore } from "next/cache" +import { GetContactPossibleItemsSchema } from "./validations" + +// 담당자별 아이템 상세 타입 정의 (뷰 기반) +export interface ContactPossibleItemDetail { + id: number + contactId: number + vendorPossibleItemId: number + createdAt: Date + updatedAt: Date + + // 벤더 정보 + vendorId: number + vendorName: string | null + vendorCode: string | null + vendorEmail: string | null + vendorPhone: string | null + vendorCountry: string | null + vendorStatus: string | null + techVendorType: string | null + + // 연락처 정보 + contactName: string | null + contactPosition: string | null + contactEmail: string | null + contactPhone: string | null + contactCountry: string | null + isPrimary: boolean | null + + // 아이템 정보 + itemCode: string | null + workType: string | null + shipTypes: string | null + itemList: string | null + subItemList: string | null +} + +/** + * 담당자별 아이템 목록 조회 (뷰 사용) + */ +export async function getContactPossibleItems(input: GetContactPossibleItemsSchema) { + unstable_noStore() + + try { + const offset = (input.page - 1) * input.per_page + + console.log("=== getContactPossibleItems DEBUG ===") + console.log("Input:", input) + console.log("Offset:", offset) + + // 검색 조건 + let whereCondition + if (input.search) { + const searchTerm = `%${input.search}%` + whereCondition = or( + ilike(techVendorPossibleItems.itemCode, searchTerm), + ilike(techVendorPossibleItems.itemList, searchTerm), + ilike(techVendors.vendorName, searchTerm), + ilike(techVendorContacts.contactName, searchTerm) + ) + console.log("Search term:", searchTerm) + } else { + console.log("No search condition") + } + + // 원본 테이블들을 직접 조인해서 데이터 조회 + console.log("Executing data query...") + const items = await db + .select({ + // 기본 매핑 정보 + id: techSalesContactPossibleItems.id, + contactId: techSalesContactPossibleItems.contactId, + vendorPossibleItemId: techSalesContactPossibleItems.vendorPossibleItemId, + createdAt: techSalesContactPossibleItems.createdAt, + updatedAt: techSalesContactPossibleItems.updatedAt, + + // 벤더 정보 + vendorId: techVendors.id, + vendorName: techVendors.vendorName, + vendorCode: techVendors.vendorCode, + vendorEmail: techVendors.email, + vendorPhone: techVendors.phone, + vendorCountry: techVendors.country, + vendorStatus: techVendors.status, + techVendorType: techVendors.techVendorType, + + // 연락처 정보 + contactName: techVendorContacts.contactName, + contactPosition: techVendorContacts.contactPosition, + contactEmail: techVendorContacts.contactEmail, + contactPhone: techVendorContacts.contactPhone, + contactCountry: techVendorContacts.contactCountry, + isPrimary: techVendorContacts.isPrimary, + + // 벤더 가능 아이템 정보 + itemCode: techVendorPossibleItems.itemCode, + workType: techVendorPossibleItems.workType, + shipTypes: techVendorPossibleItems.shipTypes, + itemList: techVendorPossibleItems.itemList, + subItemList: techVendorPossibleItems.subItemList, + }) + .from(techSalesContactPossibleItems) + .leftJoin(techVendorContacts, eq(techSalesContactPossibleItems.contactId, techVendorContacts.id)) + .leftJoin(techVendorPossibleItems, eq(techSalesContactPossibleItems.vendorPossibleItemId, techVendorPossibleItems.id)) + .leftJoin(techVendors, eq(techVendorContacts.vendorId, techVendors.id)) + .where(whereCondition) + .orderBy(desc(techSalesContactPossibleItems.createdAt)) + .offset(offset) + .limit(input.per_page) + + console.log("Items found:", items.length) + console.log("First 3 items:", items.slice(0, 3)) + + // 전체 개수 조회 (동일한 조인과 검색 조건 적용) + console.log("Executing count query...") + const [{ count: total }] = await db + .select({ count: count() }) + .from(techSalesContactPossibleItems) + .leftJoin(techVendorContacts, eq(techSalesContactPossibleItems.contactId, techVendorContacts.id)) + .leftJoin(techVendorPossibleItems, eq(techSalesContactPossibleItems.vendorPossibleItemId, techVendorPossibleItems.id)) + .leftJoin(techVendors, eq(techVendorContacts.vendorId, techVendors.id)) + .where(whereCondition) + + console.log("Total count:", total) + + const pageCount = Math.ceil(total / input.per_page) + + console.log("Final result:", { dataLength: items.length, pageCount, total }) + console.log("=== END DEBUG ===") + + return { + data: items as ContactPossibleItemDetail[], + pageCount, + total, + } + } catch (err) { + console.error("=== ERROR in getContactPossibleItems ===") + console.error("Error fetching contact possible items:", err) + console.error("Input was:", input) + console.error("=== END ERROR ===") + return { + data: [], + pageCount: 0, + total: 0, + } + } +} + +/** + * 담당자별 아이템 삭제 + */ +export async function deleteContactPossibleItem(id: number) { + try { + await db + .delete(techSalesContactPossibleItems) + .where(eq(techSalesContactPossibleItems.id, id)) + + revalidatePath("/evcp/contact-possible-items") + return { success: true } + } catch (error) { + console.error("담당자별 아이템 삭제 오류:", error) + return { success: false, error: "담당자별 아이템 삭제에 실패했습니다." } + } +} + +/** + * 여러 담당자별 아이템 삭제 + */ +export async function deleteContactPossibleItems(ids: number[]) { + try { + await db + .delete(techSalesContactPossibleItems) + .where( + or(...ids.map(id => eq(techSalesContactPossibleItems.id, id))) + ) + + revalidatePath("/evcp/contact-possible-items") + return { success: true } + } catch (error) { + console.error("담당자별 아이템 일괄 삭제 오류:", error) + return { success: false, error: "담당자별 아이템 삭제에 실패했습니다." } + } +} \ No newline at end of file -- cgit v1.2.3