summaryrefslogtreecommitdiff
path: root/lib
diff options
context:
space:
mode:
authordujinkim <dujin.kim@dtsolution.co.kr>2025-11-07 06:53:06 +0000
committerdujinkim <dujin.kim@dtsolution.co.kr>2025-11-07 06:53:06 +0000
commit121a382b2d3c547f8facce73f57dbdbcf847d879 (patch)
tree46cb96da0302ad15ba8c71829a4e3a62c1bb5db1 /lib
parent8daa2aeee017c642d2fd171094cf5d442966eb12 (diff)
(최겸) 구매 정보시스템 user vendorid 변경 기능 개발(신규)
Diffstat (limited to 'lib')
-rw-r--r--lib/change-vendor/service.ts258
1 files changed, 258 insertions, 0 deletions
diff --git a/lib/change-vendor/service.ts b/lib/change-vendor/service.ts
new file mode 100644
index 00000000..09c93a26
--- /dev/null
+++ b/lib/change-vendor/service.ts
@@ -0,0 +1,258 @@
+'use server';
+
+import { getServerSession } from 'next-auth';
+import { authOptions } from '@/app/api/auth/[...nextauth]/route';
+import db from '@/db/db';
+import { users, vendors } from '@/db/schema';
+import { and, eq, ilike, or, asc } from 'drizzle-orm';
+import { revalidatePath } from 'next/cache';
+import { getErrorMessage } from '@/lib/handle-error';
+import { unstable_noStore } from 'next/cache';
+
+/**
+ * 유저 목록 검색 (limit 100)
+ */
+export async function searchUsers(search?: string) {
+ unstable_noStore();
+
+ try {
+ const session = await getServerSession(authOptions);
+
+ if (!session?.user) {
+ return { data: null, error: '로그인이 필요합니다.' };
+ }
+
+ let whereCondition;
+
+ // 검색어가 있으면 이름 또는 이메일로 검색
+ if (search && search.trim()) {
+ const searchPattern = `%${search.trim()}%`;
+ whereCondition = or(
+ ilike(users.name, searchPattern),
+ ilike(users.email, searchPattern)
+ );
+ }
+
+ const usersList = await db
+ .select({
+ id: users.id,
+ name: users.name,
+ email: users.email,
+ companyId: users.companyId,
+ })
+ .from(users)
+ .where(whereCondition)
+ .orderBy(asc(users.name))
+ .limit(100);
+
+ return {
+ data: usersList,
+ error: null,
+ };
+ } catch (error) {
+ return { data: null, error: getErrorMessage(error) };
+ }
+}
+
+/**
+ * 특정 유저의 벤더 정보 조회
+ */
+export async function getUserVendorInfo(userId: number) {
+ unstable_noStore();
+
+ try {
+ const session = await getServerSession(authOptions);
+
+ if (!session?.user) {
+ return { data: null, error: '로그인이 필요합니다.' };
+ }
+
+ // 사용자 정보 조회
+ const user = await db
+ .select({
+ id: users.id,
+ name: users.name,
+ email: users.email,
+ companyId: users.companyId,
+ })
+ .from(users)
+ .where(eq(users.id, userId))
+ .limit(1);
+
+ if (!user[0]) {
+ return { data: null, error: '사용자를 찾을 수 없습니다.' };
+ }
+
+ // 현재 벤더 정보 조회 (companyId가 있는 경우)
+ let vendor = null;
+ if (user[0].companyId) {
+ const vendorResult = await db
+ .select({
+ id: vendors.id,
+ vendorName: vendors.vendorName,
+ vendorCode: vendors.vendorCode,
+ })
+ .from(vendors)
+ .where(eq(vendors.id, user[0].companyId))
+ .limit(1);
+
+ vendor = vendorResult[0] || null;
+ }
+
+ return {
+ data: {
+ userId: user[0].id,
+ userName: user[0].name,
+ userEmail: user[0].email,
+ currentVendorId: user[0].companyId,
+ currentVendorName: vendor?.vendorName || null,
+ currentVendorCode: vendor?.vendorCode || null,
+ },
+ error: null,
+ };
+ } catch (error) {
+ return { data: null, error: getErrorMessage(error) };
+ }
+}
+
+/**
+ * 벤더 목록 조회 (활성 상태만, 검색 기능 포함, limit 100)
+ */
+export async function getVendorList(search?: string) {
+ unstable_noStore();
+
+ try {
+ const statusCondition = eq(vendors.status, 'ACTIVE');
+
+ // 검색어가 있으면 벤더명 또는 벤더코드로 검색
+ if (search && search.trim()) {
+ const searchPattern = `%${search.trim()}%`;
+ const searchConditions = [
+ ilike(vendors.vendorName, searchPattern),
+ ilike(vendors.vendorCode, searchPattern),
+ ];
+
+ const whereCondition = and(
+ statusCondition,
+ or(...searchConditions)
+ );
+
+ const vendorsList = await db
+ .select({
+ id: vendors.id,
+ vendorName: vendors.vendorName,
+ vendorCode: vendors.vendorCode,
+ status: vendors.status,
+ })
+ .from(vendors)
+ .where(whereCondition)
+ .orderBy(asc(vendors.vendorName))
+ .limit(100);
+
+ return {
+ data: vendorsList,
+ error: null,
+ };
+ }
+
+ // 검색어가 없으면 활성 상태만 조회
+ const whereCondition = statusCondition;
+
+ const vendorsList = await db
+ .select({
+ id: vendors.id,
+ vendorName: vendors.vendorName,
+ vendorCode: vendors.vendorCode,
+ status: vendors.status,
+ })
+ .from(vendors)
+ .where(whereCondition)
+ .orderBy(asc(vendors.vendorName))
+ .limit(100);
+
+ return {
+ data: vendorsList,
+ error: null,
+ };
+ } catch (error) {
+ return { data: null, error: getErrorMessage(error) };
+ }
+}
+
+/**
+ * 벤더 변경 서버 액션 (특정 유저의 벤더 변경)
+ */
+export async function changeVendor(userId: number, newVendorId: number) {
+ unstable_noStore();
+
+ try {
+ const session = await getServerSession(authOptions);
+
+ if (!session?.user) {
+ return { success: false, error: '로그인이 필요합니다.' };
+ }
+
+ // 대상 사용자 확인
+ const targetUser = await db
+ .select({
+ id: users.id,
+ name: users.name,
+ email: users.email,
+ })
+ .from(users)
+ .where(eq(users.id, userId))
+ .limit(1);
+
+ if (!targetUser[0]) {
+ return { success: false, error: '사용자를 찾을 수 없습니다.' };
+ }
+
+ // 새 벤더 정보 확인
+ const newVendor = await db
+ .select({
+ id: vendors.id,
+ vendorName: vendors.vendorName,
+ vendorCode: vendors.vendorCode,
+ status: vendors.status,
+ })
+ .from(vendors)
+ .where(eq(vendors.id, newVendorId))
+ .limit(1);
+
+ if (!newVendor[0]) {
+ return { success: false, error: '벤더를 찾을 수 없습니다.' };
+ }
+
+ if (newVendor[0].status !== 'ACTIVE') {
+ return { success: false, error: '활성 상태인 벤더만 선택할 수 있습니다.' };
+ }
+
+ // 사용자의 companyId 업데이트
+ await db
+ .update(users)
+ .set({
+ companyId: newVendorId,
+ updatedAt: new Date(),
+ })
+ .where(eq(users.id, userId));
+
+ // 세션 재검증을 위해 경로 재검증
+ revalidatePath('/', 'layout');
+
+ return {
+ success: true,
+ data: {
+ userId: targetUser[0].id,
+ userName: targetUser[0].name,
+ userEmail: targetUser[0].email,
+ vendorId: newVendor[0].id,
+ vendorName: newVendor[0].vendorName,
+ vendorCode: newVendor[0].vendorCode,
+ },
+ error: null,
+ };
+ } catch (error) {
+ return { success: false, error: getErrorMessage(error) };
+ }
+}
+