summaryrefslogtreecommitdiff
path: root/lib/contact-possible-items/service-add-mapping.ts
diff options
context:
space:
mode:
Diffstat (limited to 'lib/contact-possible-items/service-add-mapping.ts')
-rw-r--r--lib/contact-possible-items/service-add-mapping.ts312
1 files changed, 312 insertions, 0 deletions
diff --git a/lib/contact-possible-items/service-add-mapping.ts b/lib/contact-possible-items/service-add-mapping.ts
new file mode 100644
index 00000000..39215549
--- /dev/null
+++ b/lib/contact-possible-items/service-add-mapping.ts
@@ -0,0 +1,312 @@
+"use server"
+
+import { revalidatePath } from 'next/cache'
+import { eq, and, or, ilike, inArray } from 'drizzle-orm'
+import db from '@/db/db'
+import { techSalesContactPossibleItems } from "@/db/schema/techSales"
+import { techVendors, techVendorContacts, techVendorPossibleItems } from "@/db/schema/techVendors"
+import { itemShipbuilding, itemOffshoreTop, itemOffshoreHull } from "@/db/schema/items"
+
+/**
+ * 조선 아이템 검색
+ */
+export async function searchShipbuildingItems(search: string = "") {
+ try {
+ const where = search
+ ? or(
+ ilike(itemShipbuilding.itemCode, `%${search}%`),
+ ilike(itemShipbuilding.itemList, `%${search}%`),
+ ilike(itemShipbuilding.workType, `%${search}%`),
+ ilike(itemShipbuilding.shipTypes, `%${search}%`)
+ )
+ : undefined
+
+ const items = await db
+ .select({
+ id: itemShipbuilding.id,
+ itemCode: itemShipbuilding.itemCode,
+ itemList: itemShipbuilding.itemList,
+ workType: itemShipbuilding.workType,
+ shipTypes: itemShipbuilding.shipTypes,
+ })
+ .from(itemShipbuilding)
+ .where(where)
+ .limit(100)
+
+ return { data: items, error: null }
+ } catch (err) {
+ console.error("조선 아이템 검색 오류:", err)
+ return { data: [], error: "조선 아이템 검색에 실패했습니다." }
+ }
+}
+
+/**
+ * 해양 TOP 아이템 검색
+ */
+export async function searchOffshoreTopItems(search: string = "") {
+ try {
+ const where = search
+ ? or(
+ ilike(itemOffshoreTop.itemCode, `%${search}%`),
+ ilike(itemOffshoreTop.itemList, `%${search}%`),
+ ilike(itemOffshoreTop.workType, `%${search}%`)
+ )
+ : undefined
+
+ const items = await db
+ .select({
+ id: itemOffshoreTop.id,
+ itemCode: itemOffshoreTop.itemCode,
+ itemList: itemOffshoreTop.itemList,
+ workType: itemOffshoreTop.workType,
+ subItemList: itemOffshoreTop.subItemList,
+ })
+ .from(itemOffshoreTop)
+ .where(where)
+ .limit(100)
+
+ return { data: items, error: null }
+ } catch (err) {
+ console.error("해양 TOP 아이템 검색 오류:", err)
+ return { data: [], error: "해양 TOP 아이템 검색에 실패했습니다." }
+ }
+}
+
+/**
+ * 해양 HULL 아이템 검색
+ */
+export async function searchOffshoreHullItems(search: string = "") {
+ try {
+ const where = search
+ ? or(
+ ilike(itemOffshoreHull.itemCode, `%${search}%`),
+ ilike(itemOffshoreHull.itemList, `%${search}%`),
+ ilike(itemOffshoreHull.workType, `%${search}%`)
+ )
+ : undefined
+
+ const items = await db
+ .select({
+ id: itemOffshoreHull.id,
+ itemCode: itemOffshoreHull.itemCode,
+ itemList: itemOffshoreHull.itemList,
+ workType: itemOffshoreHull.workType,
+ subItemList: itemOffshoreHull.subItemList,
+ })
+ .from(itemOffshoreHull)
+ .where(where)
+ .limit(100)
+
+ return { data: items, error: null }
+ } catch (err) {
+ console.error("해양 HULL 아이템 검색 오류:", err)
+ return { data: [], error: "해양 HULL 아이템 검색에 실패했습니다." }
+ }
+}
+
+/**
+ * 기술영업 벤더 검색
+ */
+export async function searchTechVendors(search: string = "") {
+ try {
+ const where = search
+ ? or(
+ ilike(techVendors.vendorCode, `%${search}%`),
+ ilike(techVendors.vendorName, `%${search}%`),
+ ilike(techVendors.email, `%${search}%`)
+ )
+ : undefined
+
+ const vendors = await db
+ .select({
+ id: techVendors.id,
+ vendorCode: techVendors.vendorCode,
+ vendorName: techVendors.vendorName,
+ email: techVendors.email,
+ techVendorType: techVendors.techVendorType,
+ status: techVendors.status,
+ })
+ .from(techVendors)
+ .where(where)
+ .limit(100)
+
+ return { data: vendors, error: null }
+ } catch (err) {
+ console.error("벤더 검색 오류:", err)
+ return { data: [], error: "벤더 검색에 실패했습니다." }
+ }
+}
+
+/**
+ * 여러 벤더의 담당자 조회
+ */
+export async function getTechVendorsContactsForMapping(vendorIds: number[]) {
+ try {
+ if (vendorIds.length === 0) {
+ return { data: {}, error: null }
+ }
+
+ const contactsWithVendor = await db
+ .select({
+ contactId: techVendorContacts.id,
+ contactName: techVendorContacts.contactName,
+ contactPosition: techVendorContacts.contactPosition,
+ contactTitle: techVendorContacts.contactTitle,
+ contactEmail: techVendorContacts.contactEmail,
+ contactPhone: techVendorContacts.contactPhone,
+ isPrimary: techVendorContacts.isPrimary,
+ vendorId: techVendorContacts.vendorId,
+ vendorName: techVendors.vendorName,
+ vendorCode: techVendors.vendorCode
+ })
+ .from(techVendorContacts)
+ .leftJoin(techVendors, eq(techVendorContacts.vendorId, techVendors.id))
+ .where(inArray(techVendorContacts.vendorId, vendorIds))
+
+ // 벤더별로 그룹화
+ const contactsByVendor = contactsWithVendor.reduce((acc, row) => {
+ const vendorId = row.vendorId
+ if (!acc[vendorId]) {
+ acc[vendorId] = {
+ vendor: {
+ id: vendorId,
+ vendorName: row.vendorName || '',
+ vendorCode: row.vendorCode || ''
+ },
+ contacts: []
+ }
+ }
+ acc[vendorId].contacts.push({
+ id: row.contactId,
+ contactName: row.contactName,
+ contactPosition: row.contactPosition,
+ contactTitle: row.contactTitle,
+ contactEmail: row.contactEmail,
+ contactPhone: row.contactPhone,
+ isPrimary: row.isPrimary
+ })
+ return acc
+ }, {} as Record<number, {
+ vendor: {
+ id: number
+ vendorName: string
+ vendorCode: string | null
+ }
+ contacts: Array<{
+ id: number
+ contactName: string
+ contactPosition: string | null
+ contactTitle: string | null
+ contactEmail: string
+ contactPhone: string | null
+ isPrimary: boolean
+ }>
+ }>)
+
+ return { data: contactsByVendor, error: null }
+ } catch (err) {
+ console.error("벤더 담당자 조회 오류:", err)
+ return { data: {}, error: "벤더 담당자 조회에 실패했습니다." }
+ }
+}
+
+/**
+ * 담당자-아이템 매핑 추가
+ * 선택된 아이템과 벤더를 기준으로 possible-items 테이블에 정보가 있으면 해당 id 사용,
+ * 없으면 possible-items 테이블에 insert 후, insert한 id를 가지고 담당자와 연결
+ */
+interface AddContactItemMappingInput {
+ items: {
+ id: number
+ type: 'SHIP' | 'TOP' | 'HULL'
+ }[]
+ vendors: number[]
+ contactsByVendor: Record<number, number[]> // vendorId -> contactIds[]
+}
+
+export async function addContactItemMapping(input: AddContactItemMappingInput) {
+ try {
+ return await db.transaction(async (tx) => {
+ const insertedMappings: Array<typeof techSalesContactPossibleItems.$inferSelect> = []
+
+ // 각 아이템 x 벤더 조합에 대해 처리
+ for (const item of input.items) {
+ for (const vendorId of input.vendors) {
+ const contactIds = input.contactsByVendor[vendorId] || []
+ if (contactIds.length === 0) continue
+
+ // techVendorPossibleItems에서 기존 항목 찾기
+ let vendorPossibleItemId: number | null = null
+
+ const whereCondition = and(
+ eq(techVendorPossibleItems.vendorId, vendorId),
+ item.type === 'SHIP'
+ ? eq(techVendorPossibleItems.shipbuildingItemId, item.id)
+ : item.type === 'TOP'
+ ? eq(techVendorPossibleItems.offshoreTopItemId, item.id)
+ : eq(techVendorPossibleItems.offshoreHullItemId, item.id)
+ )
+
+ const existingPossibleItem = await tx
+ .select({ id: techVendorPossibleItems.id })
+ .from(techVendorPossibleItems)
+ .where(whereCondition)
+ .limit(1)
+
+ if (existingPossibleItem.length > 0) {
+ vendorPossibleItemId = existingPossibleItem[0].id
+ } else {
+ // 없으면 새로 생성
+ const newPossibleItem = await tx
+ .insert(techVendorPossibleItems)
+ .values({
+ vendorId,
+ shipbuildingItemId: item.type === 'SHIP' ? item.id : null,
+ offshoreTopItemId: item.type === 'TOP' ? item.id : null,
+ offshoreHullItemId: item.type === 'HULL' ? item.id : null,
+ })
+ .returning({ id: techVendorPossibleItems.id })
+
+ vendorPossibleItemId = newPossibleItem[0].id
+ }
+
+ // 각 담당자에 대해 techSalesContactPossibleItems에 추가
+ for (const contactId of contactIds) {
+ // 중복 체크
+ const existing = await tx
+ .select({ id: techSalesContactPossibleItems.id })
+ .from(techSalesContactPossibleItems)
+ .where(
+ and(
+ eq(techSalesContactPossibleItems.contactId, contactId),
+ eq(techSalesContactPossibleItems.vendorPossibleItemId, vendorPossibleItemId)
+ )
+ )
+ .limit(1)
+
+ if (existing.length === 0) {
+ const inserted = await tx
+ .insert(techSalesContactPossibleItems)
+ .values({
+ contactId,
+ vendorPossibleItemId,
+ })
+ .returning()
+
+ if (inserted.length > 0) {
+ insertedMappings.push(inserted[0])
+ }
+ }
+ }
+ }
+ }
+
+ revalidatePath("/evcp/contact-possible-items")
+ return { data: insertedMappings, error: null }
+ })
+ } catch (err) {
+ console.error("담당자-아이템 매핑 추가 오류:", err)
+ return { data: null, error: "담당자-아이템 매핑 추가에 실패했습니다." }
+ }
+}
+