summaryrefslogtreecommitdiff
path: root/lib/contact-possible-items/service.ts
diff options
context:
space:
mode:
authordujinkim <dujin.kim@dtsolution.co.kr>2025-07-21 07:54:26 +0000
committerdujinkim <dujin.kim@dtsolution.co.kr>2025-07-21 07:54:26 +0000
commit14f61e24947fb92dd71ec0a7196a6e815f8e66da (patch)
tree317c501d64662d05914330628f867467fba78132 /lib/contact-possible-items/service.ts
parent194bd4bd7e6144d5c09c5e3f5476d254234dce72 (diff)
(최겸)기술영업 RFQ 담당자 초대, 요구사항 반영
Diffstat (limited to 'lib/contact-possible-items/service.ts')
-rw-r--r--lib/contact-possible-items/service.ts190
1 files changed, 190 insertions, 0 deletions
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