summaryrefslogtreecommitdiff
path: root/lib/vendors/service.ts
diff options
context:
space:
mode:
Diffstat (limited to 'lib/vendors/service.ts')
-rw-r--r--lib/vendors/service.ts160
1 files changed, 158 insertions, 2 deletions
diff --git a/lib/vendors/service.ts b/lib/vendors/service.ts
index 6132832f..de88ae72 100644
--- a/lib/vendors/service.ts
+++ b/lib/vendors/service.ts
@@ -1818,12 +1818,168 @@ export async function approveVendors(input: ApproveVendorsInput & { userId: numb
}
/**
+ * 선택된 벤더의 상태를 REJECTED로 변경하고 이메일 알림을 발송하는 서버 액션
+ */
+export async function rejectVendors(input: ApproveVendorsInput & { userId: number }) {
+ unstable_noStore();
+
+ try {
+ // 트랜잭션 내에서 협력업체 상태 업데이트 및 이메일 발송
+ const result = await db.transaction(async (tx) => {
+ // 0. 업데이트 전 협력업체 상태 조회
+ const vendorsBeforeUpdate = await tx
+ .select({
+ id: vendors.id,
+ status: vendors.status,
+ })
+ .from(vendors)
+ .where(inArray(vendors.id, input.ids));
+
+ // 1. 협력업체 상태 업데이트
+ const [updated] = await tx
+ .update(vendors)
+ .set({
+ status: "REJECTED",
+ updatedAt: new Date()
+ })
+ .where(inArray(vendors.id, input.ids))
+ .returning();
+
+ // 2. 업데이트된 협력업체 정보 조회 (국가 정보 포함)
+ const updatedVendors = await tx
+ .select({
+ id: vendors.id,
+ vendorName: vendors.vendorName,
+ email: vendors.email,
+ country: vendors.country, // 언어 설정용 국가 정보
+ })
+ .from(vendors)
+ .where(inArray(vendors.id, input.ids));
+
+ // 3. 각 벤더에 대한 유저 계정 비활성화 처리
+ await Promise.all(
+ updatedVendors.map(async (vendor) => {
+ if (!vendor.email) return; // 이메일이 없으면 스킵
+
+ // 기존 유저 확인
+ const existingUser = await tx
+ .select({
+ id: users.id,
+ isActive: users.isActive,
+ language: users.language,
+ })
+ .from(users)
+ .where(eq(users.email, vendor.email))
+ .limit(1);
+
+ if (existingUser.length > 0) {
+ // 기존 사용자 존재 시 - 비활성화
+ const user = existingUser[0];
+ console.log(`👤 기존 사용자 발견: ${vendor.email} (활성상태: ${user.isActive})`);
+
+ if (user.isActive) {
+ // 활성 사용자 비활성화
+ await tx
+ .update(users)
+ .set({
+ isActive: false,
+ updatedAt: new Date(),
+ })
+ .where(eq(users.id, user.id));
+
+ console.log(`❌ 사용자 비활성화 완료: ${vendor.email} (ID: ${user.id})`);
+ } else {
+ console.log(`ℹ️ 사용자가 이미 비활성 상태: ${vendor.email}`);
+ }
+ }
+ })
+ );
+
+ // 4. 로그 기록
+ await Promise.all(
+ vendorsBeforeUpdate.map(async (vendorBefore) => {
+ await tx.insert(vendorsLogs).values({
+ vendorId: vendorBefore.id,
+ userId: input.userId,
+ action: "status_change",
+ oldStatus: vendorBefore.status,
+ newStatus: "REJECTED",
+ comment: "Vendor rejected",
+ });
+ })
+ );
+
+ // 5. 각 벤더에게 거절 이메일 발송
+ await Promise.all(
+ updatedVendors.map(async (vendor) => {
+ if (!vendor.email) return; // 이메일이 없으면 스킵
+
+ try {
+ // 사용자 언어 확인
+ const userInfo = await tx
+ .select({
+ id: users.id,
+ language: users.language
+ })
+ .from(users)
+ .where(eq(users.email, vendor.email))
+ .limit(1);
+
+ const userLang = userInfo.length > 0 ? userInfo[0].language :
+ (vendor.country === 'KR' ? 'ko' : 'en');
+
+ const subject = userLang === 'ko'
+ ? "[eVCP] 업체 등록 거절 안내"
+ : "[eVCP] Vendor Registration Rejected";
+
+ const headersList = await headers();
+ const host = headersList.get('host') || 'localhost:3000';
+ const protocol = headersList.get('x-forwarded-proto') || 'http';
+ const baseUrl = `${protocol}://${host}`;
+ const loginUrl = `${baseUrl}/${userLang}/login`;
+
+ await sendEmail({
+ to: vendor.email,
+ subject,
+ template: "vendor-rejected", // 거절 템플릿
+ context: {
+ vendorName: vendor.vendorName,
+ loginUrl,
+ language: userLang,
+ },
+ });
+
+ console.log(`📧 거절 이메일 발송: ${vendor.email}`);
+ } catch (emailError) {
+ console.error(`이메일 발송 실패 - 업체 ${vendor.id}:`, emailError);
+ // 이메일 전송 실패는 전체 트랜잭션을 실패시키지 않음
+ }
+ })
+ );
+
+ console.log(`❌ 협력업체 거절 완료: ${updatedVendors.length}개 업체`);
+ return updated;
+ });
+
+ // 캐시 무효화
+ revalidateTag("vendors");
+ revalidateTag("vendor-status-counts");
+ revalidateTag("users"); // 유저 캐시도 무효화
+
+ return { data: result, error: null };
+ } catch (err) {
+ console.error("협력업체 거절 처리 오류:", err);
+ return { data: null, error: getErrorMessage(err) };
+ }
+}
+
+/**
* 유니크한 PQ 번호 생성 함수
- *
+ *
* 형식: PQ-YYMMDD-XXXXX
* YYMMDD: 연도(YY), 월(MM), 일(DD)
* XXXXX: 시퀀스 번호 (00001부터 시작)
- *
+ *
* 예: PQ-240520-00001, PQ-240520-00002, ...
*/
export async function generatePQNumber(isProject: boolean = false) {