summaryrefslogtreecommitdiff
path: root/lib/tech-vendors/service.ts
diff options
context:
space:
mode:
authorjoonhoekim <26rote@gmail.com>2025-06-24 01:51:59 +0000
committerjoonhoekim <26rote@gmail.com>2025-06-24 01:51:59 +0000
commit6824e097d768f724cf439b410ccfb1ab9685ac98 (patch)
tree1f297313637878e7a4ad6c89b84d5a2c3e9eb650 /lib/tech-vendors/service.ts
parentf4825dd3853188de4688fb4a56c0f4e847da314b (diff)
parent4e63d8427d26d0d1b366ddc53650e15f3481fc75 (diff)
(merge) 대표님/최겸 작업사항 머지
Diffstat (limited to 'lib/tech-vendors/service.ts')
-rw-r--r--lib/tech-vendors/service.ts180
1 files changed, 171 insertions, 9 deletions
diff --git a/lib/tech-vendors/service.ts b/lib/tech-vendors/service.ts
index 05ec1178..5fd5ef02 100644
--- a/lib/tech-vendors/service.ts
+++ b/lib/tech-vendors/service.ts
@@ -2,7 +2,7 @@
import { revalidateTag, unstable_noStore } from "next/cache";
import db from "@/db/db";
-import { techVendorAttachments, techVendorContacts, techVendorPossibleItems, techVendors, techVendorItemsView, type TechVendor } from "@/db/schema/techVendors";
+import { techVendorAttachments, techVendorContacts, techVendorPossibleItems, techVendors, techVendorItemsView, type TechVendor, techVendorCandidates } from "@/db/schema/techVendors";
import { items, itemShipbuilding, itemOffshoreTop, itemOffshoreHull } from "@/db/schema/items";
import { filterColumns } from "@/lib/filter-columns";
@@ -78,6 +78,25 @@ export async function getTechVendors(input: GetTechVendorsSchema) {
// 최종 where 결합
const finalWhere = and(advancedWhere, globalWhere);
+ // 벤더 타입 필터링 로직 추가
+ let vendorTypeWhere;
+ if (input.vendorType) {
+ // URL의 vendorType 파라미터를 실제 벤더 타입으로 매핑
+ const vendorTypeMap = {
+ "ship": "조선",
+ "top": "해양TOP",
+ "hull": "해양HULL"
+ };
+
+ const actualVendorType = input.vendorType in vendorTypeMap
+ ? vendorTypeMap[input.vendorType as keyof typeof vendorTypeMap]
+ : undefined;
+ if (actualVendorType) {
+ // techVendorType 필드는 콤마로 구분된 문자열이므로 LIKE 사용
+ vendorTypeWhere = ilike(techVendors.techVendorType, `%${actualVendorType}%`);
+ }
+ }
+
// 간단 검색 (advancedTable=false) 시 예시
const simpleWhere = and(
input.vendorName
@@ -89,8 +108,8 @@ export async function getTechVendors(input: GetTechVendorsSchema) {
: undefined
);
- // 실제 사용될 where
- const where = finalWhere;
+ // 실제 사용될 where (vendorType 필터링 추가)
+ const where = and(finalWhere, vendorTypeWhere);
// 정렬
const orderBy =
@@ -272,7 +291,7 @@ export async function createTechVendor(input: CreateTechVendorSchema) {
phone: input.phone || null,
email: input.email,
website: input.website || null,
- techVendorType: input.techVendorType as "조선" | "해양TOP" | "해양HULL",
+ techVendorType: Array.isArray(input.techVendorType) ? input.techVendorType.join(',') : input.techVendorType,
representativeName: input.representativeName || null,
representativeBirth: input.representativeBirth || null,
representativeEmail: input.representativeEmail || null,
@@ -1066,9 +1085,9 @@ export async function exportTechVendorDetails(vendorIds: number[]) {
}
/**
- * 기술영업 벤더 상세 정보 조회
+ * 기술영업 벤더 상세 정보 조회 (연락처, 첨부파일 포함)
*/
-async function getTechVendorDetailById(id: number) {
+export async function getTechVendorDetailById(id: number) {
try {
const vendor = await db.select().from(techVendors).where(eq(techVendors.id, id)).limit(1);
@@ -1255,7 +1274,7 @@ export async function importTechVendorsFromExcel(
phone: vendor.phone || null,
email: vendor.email,
website: vendor.website || null,
- techVendorType: vendor.techVendorType as "조선" | "해양TOP" | "해양HULL",
+ techVendorType: vendor.techVendorType,
status: "ACTIVE",
representativeName: vendor.representativeName || null,
representativeEmail: vendor.representativeEmail || null,
@@ -1345,6 +1364,149 @@ export async function findTechVendorById(id: number): Promise<TechVendor | null>
}
/**
+ * 회원가입 폼을 통한 기술영업 벤더 생성 (초대 토큰 기반)
+ */
+export async function createTechVendorFromSignup(params: {
+ vendorData: {
+ vendorName: string
+ vendorCode?: string
+ items: string
+ website?: string
+ taxId: string
+ address?: string
+ email: string
+ phone?: string
+ country: string
+ techVendorType: "조선" | "해양TOP" | "해양HULL"
+ representativeName?: string
+ representativeBirth?: string
+ representativeEmail?: string
+ representativePhone?: string
+ }
+ files?: File[]
+ contacts: {
+ contactName: string
+ contactPosition?: string
+ contactEmail: string
+ contactPhone?: string
+ isPrimary?: boolean
+ }[]
+ invitationToken?: string // 초대 토큰
+}) {
+ unstable_noStore();
+
+ try {
+ console.log("기술영업 벤더 회원가입 시작:", params.vendorData.vendorName);
+
+ const result = await db.transaction(async (tx) => {
+ // 1. 이메일 중복 체크
+ const existingVendor = await tx.query.techVendors.findFirst({
+ where: eq(techVendors.email, params.vendorData.email),
+ columns: { id: true, vendorName: true }
+ });
+
+ if (existingVendor) {
+ throw new Error(`이미 등록된 이메일입니다: ${params.vendorData.email}`);
+ }
+
+ // 2. 벤더 생성
+ const [newVendor] = await tx.insert(techVendors).values({
+ vendorName: params.vendorData.vendorName,
+ vendorCode: params.vendorData.vendorCode || null,
+ taxId: params.vendorData.taxId,
+ country: params.vendorData.country,
+ address: params.vendorData.address || null,
+ phone: params.vendorData.phone || null,
+ email: params.vendorData.email,
+ website: params.vendorData.website || null,
+ techVendorType: params.vendorData.techVendorType,
+ status: "ACTIVE",
+ representativeName: params.vendorData.representativeName || null,
+ representativeEmail: params.vendorData.representativeEmail || null,
+ representativePhone: params.vendorData.representativePhone || null,
+ representativeBirth: params.vendorData.representativeBirth || null,
+ items: params.vendorData.items,
+ }).returning();
+
+ console.log("기술영업 벤더 생성 성공:", newVendor.id);
+
+ // 3. 연락처 생성
+ if (params.contacts && params.contacts.length > 0) {
+ for (const [index, contact] of params.contacts.entries()) {
+ await tx.insert(techVendorContacts).values({
+ vendorId: newVendor.id,
+ contactName: contact.contactName,
+ contactPosition: contact.contactPosition || null,
+ contactEmail: contact.contactEmail,
+ contactPhone: contact.contactPhone || null,
+ isPrimary: index === 0, // 첫 번째 연락처를 primary로 설정
+ });
+ }
+ console.log("연락처 생성 완료:", params.contacts.length, "개");
+ }
+
+ // 4. 첨부파일 처리
+ if (params.files && params.files.length > 0) {
+ await storeTechVendorFiles(tx, newVendor.id, params.files, "GENERAL");
+ console.log("첨부파일 저장 완료:", params.files.length, "개");
+ }
+
+ // 5. 유저 생성 (techCompanyId 설정)
+ console.log("유저 생성 시도:", params.vendorData.email);
+
+ const existingUser = await tx.query.users.findFirst({
+ where: eq(users.email, params.vendorData.email),
+ columns: { id: true, techCompanyId: true }
+ });
+
+ let userId = null;
+ if (!existingUser) {
+ const [newUser] = await tx.insert(users).values({
+ name: params.vendorData.vendorName,
+ email: params.vendorData.email,
+ techCompanyId: newVendor.id, // 중요: techCompanyId 설정
+ domain: "partners",
+ }).returning();
+ userId = newUser.id;
+ console.log("유저 생성 성공:", userId);
+ } else {
+ // 기존 유저의 techCompanyId 업데이트
+ if (!existingUser.techCompanyId) {
+ await tx.update(users)
+ .set({ techCompanyId: newVendor.id })
+ .where(eq(users.id, existingUser.id));
+ console.log("기존 유저의 techCompanyId 업데이트:", existingUser.id);
+ }
+ userId = existingUser.id;
+ }
+
+ // 6. 후보에서 해당 이메일이 있으면 vendorId 업데이트 및 상태 변경
+ if (params.vendorData.email) {
+ await tx.update(techVendorCandidates)
+ .set({
+ vendorId: newVendor.id,
+ status: "INVITED"
+ })
+ .where(eq(techVendorCandidates.contactEmail, params.vendorData.email));
+ }
+
+ return { vendor: newVendor, userId };
+ });
+
+ // 캐시 무효화
+ revalidateTag("tech-vendors");
+ revalidateTag("tech-vendor-candidates");
+ revalidateTag("users");
+
+ console.log("기술영업 벤더 회원가입 완료:", result);
+ return { success: true, data: result };
+ } catch (error) {
+ console.error("기술영업 벤더 회원가입 실패:", error);
+ return { success: false, error: getErrorMessage(error) };
+ }
+}
+
+/**
* 단일 기술영업 벤더 추가 (사용자 계정도 함께 생성)
*/
export async function addTechVendor(input: {
@@ -1361,7 +1523,7 @@ export async function addTechVendor(input: {
address?: string | null;
phone?: string | null;
website?: string | null;
- techVendorType: "조선" | "해양TOP" | "해양HULL";
+ techVendorType: string;
representativeName?: string | null;
representativeEmail?: string | null;
representativePhone?: string | null;
@@ -1404,7 +1566,7 @@ export async function addTechVendor(input: {
phone: input.phone || null,
email: input.email,
website: input.website || null,
- techVendorType: input.techVendorType,
+ techVendorType: Array.isArray(input.techVendorType) ? input.techVendorType.join(',') : input.techVendorType,
status: "ACTIVE",
representativeName: input.representativeName || null,
representativeEmail: input.representativeEmail || null,