diff options
| author | dujinkim <dujin.kim@dtsolution.co.kr> | 2025-08-22 02:12:15 +0000 |
|---|---|---|
| committer | dujinkim <dujin.kim@dtsolution.co.kr> | 2025-08-22 02:12:15 +0000 |
| commit | 7dd2b9fc1856306652f311d19697d9880955bfab (patch) | |
| tree | 3144f14e2b6e9d66c25f10686ca9e94d61d9154e /lib | |
| parent | 94082bfe915d3b0337f8929a2bb27828abb5d3c7 (diff) | |
(최겸) 공지사항, 인포메이션 기능 수정
Diffstat (limited to 'lib')
| -rw-r--r-- | lib/information/service.ts | 74 | ||||
| -rw-r--r-- | lib/information/table/update-information-dialog.tsx | 4 | ||||
| -rw-r--r-- | lib/notice/repository.ts | 155 | ||||
| -rw-r--r-- | lib/notice/service.ts | 215 | ||||
| -rw-r--r-- | lib/notice/validations.ts | 57 | ||||
| -rw-r--r-- | lib/vendor-regular-registrations/repository.ts | 35 | ||||
| -rw-r--r-- | lib/vendor-regular-registrations/service.ts | 13 |
7 files changed, 135 insertions, 418 deletions
diff --git a/lib/information/service.ts b/lib/information/service.ts index 2826c0e9..2d3ad079 100644 --- a/lib/information/service.ts +++ b/lib/information/service.ts @@ -1,8 +1,6 @@ "use server" -import { revalidateTag } from "next/cache" import { getErrorMessage } from "@/lib/handle-error" -import { unstable_cache } from "@/lib/unstable-cache" import { desc, or, eq } from "drizzle-orm" import db from "@/db/db" import { pageInformation, menuAssignments } from "@/db/schema" @@ -45,22 +43,29 @@ export async function getInformationLists() { // 페이지별 인포메이션 조회 (첨부파일 포함) export async function getPageInformation(pagePath: string) { try { - return await getInformationByPagePathWithAttachments(pagePath) + console.log('🔍 Information Service - 조회 시작:', { pagePath }) + const result = await getInformationByPagePathWithAttachments(pagePath) + console.log('📊 Information Service - 조회 결과:', { + pagePath, + found: !!result, + resultData: result ? { + id: result.id, + pagePath: result.pagePath, + pageName: result.pageName, + attachmentsCount: result.attachments?.length || 0 + } : null + }) + return result } catch (error) { console.error(`Failed to get information for page ${pagePath}:`, error) return null } } -// 캐시된 페이지별 인포메이션 조회 -export const getCachedPageInformation = unstable_cache( - async (pagePath: string) => getPageInformation(pagePath), - ["page-information"], - { - tags: ["page-information"], - revalidate: 3600, // 1시간 캐시 - } -) +// 페이지별 인포메이션 조회 (직접 호출용) +export async function getPageInformationDirect(pagePath: string) { + return await getPageInformation(pagePath) +} // 인포메이션 수정 (내용과 첨부파일만) export async function updateInformationData(input: UpdateInformationSchema) { @@ -83,9 +88,7 @@ export async function updateInformationData(input: UpdateInformationSchema) { } } - revalidateTag("page-information") - revalidateTag("information-lists") - revalidateTag("information-edit-permission") // 편집 권한 캐시 무효화 + // 캐시 무효화 제거됨 return { success: true, @@ -113,13 +116,18 @@ export async function getInformationDetail(id: number) { // 인포메이션 편집 권한 확인 export async function checkInformationEditPermission(pagePath: string, userId: string): Promise<boolean> { try { + // pagePath 정규화 (앞의 / 제거) + const normalizedPagePath = pagePath.startsWith('/') ? pagePath.slice(1) : pagePath + // pagePath를 menuPath로 변환 (pagePath가 menuPath의 마지막 부분이라고 가정) // 예: pagePath "vendor-list" -> menuPath "/evcp/vendor-list" 또는 "/partners/vendor-list" const menuPathQueries = [ - `/evcp/${pagePath}`, - `/partners/${pagePath}`, - `/${pagePath}`, // 루트 경로 - pagePath // 정확한 매칭 + `/evcp/${normalizedPagePath}`, + `/partners/${normalizedPagePath}`, + `/${normalizedPagePath}`, // 루트 경로 + normalizedPagePath, // 정확한 매칭 + `/${pagePath}`, // 원본 경로도 체크 + pagePath // 원본 경로 정확한 매칭 ] // menu_assignments에서 해당 pagePath와 매칭되는 메뉴 찾기 @@ -149,15 +157,10 @@ export async function checkInformationEditPermission(pagePath: string, userId: s } } -// 캐시된 권한 확인 -export const getCachedEditPermission = unstable_cache( - async (pagePath: string, userId: string) => checkInformationEditPermission(pagePath, userId), - ["information-edit-permission"], - { - tags: ["information-edit-permission"], - revalidate: 300, // 5분 캐시 - } -) +// 권한 확인 (직접 호출용) +export async function getEditPermissionDirect(pagePath: string, userId: string) { + return await checkInformationEditPermission(pagePath, userId) +} // menu_assignments 기반으로 page_information 동기화 export async function syncInformationFromMenuAssignments() { @@ -170,9 +173,14 @@ export async function syncInformationFromMenuAssignments() { // upsert를 사용하여 각 메뉴 항목 처리 for (const menu of menuItems) { try { + // 맨 앞의 / 제거하여 pagePath 정규화 + const normalizedPagePath = menu.menuPath.startsWith('/') + ? menu.menuPath.slice(1) + : menu.menuPath; + await db.insert(pageInformation) .values({ - pagePath: menu.menuPath, + pagePath: normalizedPagePath, pageName: menu.menuTitle, informationContent: "", isActive: true // 기본값으로 활성화 @@ -191,7 +199,7 @@ export async function syncInformationFromMenuAssignments() { } } - revalidateTag("information"); + // 캐시 무효화 제거됨 return { success: true, @@ -249,8 +257,7 @@ export async function uploadInformationAttachment(formData: FormData) { } } - revalidateTag("page-information") - revalidateTag("information-lists") + // 캐시 무효화 제거됨 return { success: true, @@ -288,8 +295,7 @@ export async function deleteInformationAttachmentAction(attachmentId: number) { } } - revalidateTag("page-information") - revalidateTag("information-lists") + // 캐시 무효화 제거됨 return { success: true, diff --git a/lib/information/table/update-information-dialog.tsx b/lib/information/table/update-information-dialog.tsx index a02b6eb1..370eb763 100644 --- a/lib/information/table/update-information-dialog.tsx +++ b/lib/information/table/update-information-dialog.tsx @@ -44,7 +44,7 @@ import { downloadInformationAttachment
} from "@/lib/information/service"
import type { PageInformation, InformationAttachment } from "@/db/schema/information"
-import { downloadFile } from "@/lib/file-download"
+// downloadFile은 동적으로 import
import prettyBytes from "pretty-bytes"
const MAX_FILE_SIZE = 50 * 1024 * 1024 // 50MB
@@ -126,6 +126,8 @@ export function UpdateInformationDialog({ try {
const result = await downloadInformationAttachment(attachment.id)
if (result.success && result.data) {
+ // 동적으로 downloadFile 함수 import
+ const { downloadFile } = await import('@/lib/file-download')
await downloadFile(result.data.filePath, result.data.fileName)
toast.success("파일 다운로드가 시작되었습니다.")
} else {
diff --git a/lib/notice/repository.ts b/lib/notice/repository.ts index 84e64f00..fb941ac9 100644 --- a/lib/notice/repository.ts +++ b/lib/notice/repository.ts @@ -1,160 +1,7 @@ -import { asc, desc, eq, ilike, and, count, sql } from "drizzle-orm"
+import { desc, eq, and, sql } from "drizzle-orm"
import db from "@/db/db"
import { notice, users, type Notice, type NewNotice } from "@/db/schema"
-// 최신 패턴: 트랜잭션을 지원하는 공지사항 조회
-export async function selectNoticeLists(
- tx: typeof db,
- params: {
- where?: ReturnType<typeof and>
- orderBy?: (ReturnType<typeof asc> | ReturnType<typeof desc>)[]
- offset?: number
- limit?: number
- }
-) {
- const { where, orderBy, offset = 0, limit = 10 } = params
-
- return tx
- .select({
- id: notice.id,
- pagePath: notice.pagePath,
- title: notice.title,
- content: notice.content,
- authorId: notice.authorId,
- isActive: notice.isActive,
- createdAt: notice.createdAt,
- updatedAt: notice.updatedAt,
- authorName: users.name,
- authorEmail: users.email,
- })
- .from(notice)
- .leftJoin(users, eq(notice.authorId, users.id))
- .where(where)
- .orderBy(...(orderBy ?? [desc(notice.createdAt)]))
- .offset(offset)
- .limit(limit)
-}
-
-// 최신 패턴: 트랜잭션을 지원하는 카운트 조회
-export async function countNoticeLists(
- tx: typeof db,
- where?: ReturnType<typeof and>
-) {
- const res = await tx
- .select({ count: count() })
- .from(notice)
- .where(where)
-
- return res[0]?.count ?? 0
-}
-
-// 기존 패턴 (하위 호환성을 위해 유지)
-export async function selectNotice(input: { page: number; per_page: number; sort?: string; pagePath?: string; title?: string; authorId?: number; isActive?: boolean; from?: string; to?: string }) {
- const { page, per_page = 50, sort, pagePath, title, authorId, isActive, from, to } = input
-
- const conditions = []
-
- if (pagePath) {
- conditions.push(ilike(notice.pagePath, `%${pagePath}%`))
- }
-
- if (title) {
- conditions.push(ilike(notice.title, `%${title}%`))
- }
-
- if (authorId) {
- conditions.push(eq(notice.authorId, authorId))
- }
-
- if (isActive !== null && isActive !== undefined) {
- conditions.push(eq(notice.isActive, isActive))
- }
-
- if (from) {
- conditions.push(sql`${notice.createdAt} >= ${from}`)
- }
-
- if (to) {
- conditions.push(sql`${notice.createdAt} <= ${to}`)
- }
-
- const offset = (page - 1) * per_page
-
- // 정렬 설정
- let orderBy = desc(notice.createdAt);
-
- if (sort && Array.isArray(sort) && sort.length > 0) {
- const sortItem = sort[0];
- if (sortItem.id === "createdAt") {
- orderBy = sortItem.desc ? desc(notice.createdAt) : asc(notice.createdAt);
- }
- }
-
- const whereClause = conditions.length > 0 ? and(...conditions) : undefined
-
- const data = await db
- .select({
- id: notice.id,
- pagePath: notice.pagePath,
- title: notice.title,
- content: notice.content,
- authorId: notice.authorId,
- isActive: notice.isActive,
- createdAt: notice.createdAt,
- updatedAt: notice.updatedAt,
- authorName: users.name,
- authorEmail: users.email,
- })
- .from(notice)
- .leftJoin(users, eq(notice.authorId, users.id))
- .where(whereClause)
- .orderBy(orderBy)
- .limit(per_page)
- .offset(offset)
-
- return data
-}
-
-// 기존 패턴: 공지사항 총 개수 조회
-export async function countNotice(input: { pagePath?: string; title?: string; authorId?: number; isActive?: boolean; from?: string; to?: string }) {
- const { pagePath, title, authorId, isActive, from, to } = input
-
- const conditions = []
-
- if (pagePath) {
- conditions.push(ilike(notice.pagePath, `%${pagePath}%`))
- }
-
- if (title) {
- conditions.push(ilike(notice.title, `%${title}%`))
- }
-
- if (authorId) {
- conditions.push(eq(notice.authorId, authorId))
- }
-
- if (isActive !== null && isActive !== undefined) {
- conditions.push(eq(notice.isActive, isActive))
- }
-
- if (from) {
- conditions.push(sql`${notice.createdAt} >= ${from}`)
- }
-
- if (to) {
- conditions.push(sql`${notice.createdAt} <= ${to}`)
- }
-
- const whereClause = conditions.length > 0 ? and(...conditions) : undefined
-
- const result = await db
- .select({ count: count() })
- .from(notice)
- .where(whereClause)
-
- return result[0]?.count ?? 0
-}
-
// 페이지 경로별 공지사항 조회 (활성화된 것만, 작성자 정보 포함)
export async function getNoticesByPagePath(pagePath: string): Promise<Array<Notice & { authorName: string | null; authorEmail: string | null }>> {
const result = await db
diff --git a/lib/notice/service.ts b/lib/notice/service.ts index c261cd2e..9c05b98f 100644 --- a/lib/notice/service.ts +++ b/lib/notice/service.ts @@ -1,203 +1,81 @@ "use server"
-import { revalidateTag, unstable_noStore } from "next/cache"
import { getErrorMessage } from "@/lib/handle-error"
-import { unstable_cache } from "@/lib/unstable-cache"
-import { filterColumns } from "@/lib/filter-columns"
-import { asc, desc, ilike, and, or, eq } from "drizzle-orm"
+import { desc, eq } from "drizzle-orm"
import db from "@/db/db"
-import { notice, pageInformation, menuAssignments } from "@/db/schema"
+import { notice, pageInformation, menuAssignments, users } from "@/db/schema"
import type {
CreateNoticeSchema,
- UpdateNoticeSchema,
- GetNoticeSchema
+ UpdateNoticeSchema
} from "./validations"
import {
- selectNotice,
- countNotice,
getNoticesByPagePath,
insertNotice,
updateNotice,
deleteNoticeById,
deleteNoticeByIds,
- getNoticeById,
- selectNoticeLists,
- countNoticeLists
+ getNoticeById
} from "./repository"
import type { Notice } from "@/db/schema/notice"
-export async function getNoticeLists(input: GetNoticeSchema) {
- return unstable_cache(
- async () => {
- try {
- // 고급 검색 로직
- const { page, perPage, search, filters, joinOperator, pagePath, title, content, authorId, isActive } = input
-
- // 기본 검색 조건들
- const conditions = []
-
- // 검색어가 있으면 여러 필드에서 검색
- if (search && search.trim()) {
- const searchConditions = [
- ilike(notice.pagePath, `%${search}%`),
- ilike(notice.title, `%${search}%`),
- ilike(notice.content, `%${search}%`)
- ]
- conditions.push(or(...searchConditions))
- }
-
- // 개별 필드 조건들
- if (pagePath && pagePath.trim()) {
- conditions.push(ilike(notice.pagePath, `%${pagePath}%`))
- }
-
- if (title && title.trim()) {
- conditions.push(ilike(notice.title, `%${title}%`))
- }
-
- if (content && content.trim()) {
- conditions.push(ilike(notice.content, `%${content}%`))
- }
-
- if (authorId !== null && authorId !== undefined) {
- conditions.push(eq(notice.authorId, authorId))
- }
-
- if (isActive !== null && isActive !== undefined) {
- conditions.push(eq(notice.isActive, isActive))
- }
- // 고급 필터 처리
- if (filters && filters.length > 0) {
- const advancedConditions = filters.map(() =>
- filterColumns({
- table: notice,
- filters: filters,
- joinOperator: joinOperator,
- })
- )
-
- if (advancedConditions.length > 0) {
- if (joinOperator === "or") {
- conditions.push(or(...advancedConditions))
- } else {
- conditions.push(and(...advancedConditions))
- }
- }
- }
-
- // 전체 WHERE 조건 조합
- const finalWhere = conditions.length > 0
- ? (joinOperator === "or" ? or(...conditions) : and(...conditions))
- : undefined
-
- // 페이지네이션
- const offset = (page - 1) * perPage
-
- // 정렬 처리
- const orderBy = input.sort.length > 0
- ? input.sort.map((item) => {
- if (item.id === "createdAt") {
- return item.desc ? desc(notice.createdAt) : asc(notice.createdAt)
- } else if (item.id === "updatedAt") {
- return item.desc ? desc(notice.updatedAt) : asc(notice.updatedAt)
- } else if (item.id === "pagePath") {
- return item.desc ? desc(notice.pagePath) : asc(notice.pagePath)
- } else if (item.id === "title") {
- return item.desc ? desc(notice.title) : asc(notice.title)
- } else if (item.id === "authorId") {
- return item.desc ? desc(notice.authorId) : asc(notice.authorId)
- } else if (item.id === "isActive") {
- return item.desc ? desc(notice.isActive) : asc(notice.isActive)
- } else {
- return desc(notice.createdAt) // 기본값
- }
- })
- : [desc(notice.createdAt)]
-
- // 트랜잭션 내부에서 Repository 호출
- const { data, total } = await db.transaction(async (tx) => {
- const data = await selectNoticeLists(tx, {
- where: finalWhere,
- orderBy,
- offset,
- limit: input.perPage,
- })
-
- const total = await countNoticeLists(tx, finalWhere)
- return { data, total }
- })
-
- const pageCount = Math.ceil(total / input.perPage)
-
- return { data, pageCount, total }
- } catch (err) {
- console.error("Failed to get notice lists:", err)
- // 에러 발생 시 기본값 반환
- return { data: [], pageCount: 0, total: 0 }
- }
- },
- [JSON.stringify(input)],
- {
- revalidate: 3600,
- tags: ["notice-lists"],
- }
- )()
-}
-
-// 기존 패턴 (하위 호환성을 위해 유지)
-export async function getNoticeList(input: Partial<{ page: number; per_page: number; sort?: string; pagePath?: string; title?: string; authorId?: number; isActive?: boolean; from?: string; to?: string }> & { page: number; per_page: number }) {
- unstable_noStore()
-
+// 간단한 공지사항 목록 조회 (페이지네이션 없이 전체 조회)
+export async function getNoticeLists(): Promise<{ data: Array<Notice & { authorName: string | null; authorEmail: string | null }> }> {
try {
- const [data, total] = await Promise.all([
- selectNotice(input),
- countNotice(input)
- ])
-
- const pageCount = Math.ceil(total / input.per_page)
-
- return {
- data,
- pageCount,
- total
- }
- } catch (error) {
- console.error("Failed to get notice list:", error)
- throw new Error(getErrorMessage(error))
+ // 전체 데이터 조회 (작성자 정보 포함, 클라이언트에서 검색 처리)
+ const data = await db
+ .select({
+ id: notice.id,
+ pagePath: notice.pagePath,
+ title: notice.title,
+ content: notice.content,
+ authorId: notice.authorId,
+ isActive: notice.isActive,
+ createdAt: notice.createdAt,
+ updatedAt: notice.updatedAt,
+ authorName: users.name,
+ authorEmail: users.email,
+ })
+ .from(notice)
+ .leftJoin(users, eq(notice.authorId, users.id))
+ .orderBy(desc(notice.createdAt))
+
+ return { data }
+ } catch (err) {
+ console.error("Failed to get notice lists:", err)
+ return { data: [] }
}
}
// 페이지별 공지사항 조회 (일반 사용자용)
export async function getPageNotices(pagePath: string): Promise<Array<Notice & { authorName: string | null; authorEmail: string | null }>> {
try {
- return await getNoticesByPagePath(pagePath)
+ console.log('🔍 Notice Service - 조회 시작:', { pagePath })
+ const result = await getNoticesByPagePath(pagePath)
+ console.log('📊 Notice Service - 조회 결과:', {
+ pagePath,
+ noticesCount: result.length,
+ notices: result.map(n => ({ id: n.id, title: n.title, pagePath: n.pagePath }))
+ })
+ return result
} catch (error) {
console.error(`Failed to get notices for page ${pagePath}:`, error)
return []
}
}
-// 캐시된 페이지별 공지사항 조회
-export const getCachedPageNotices = unstable_cache(
- async (pagePath: string) => getPageNotices(pagePath),
- ["page-notices"],
- {
- tags: ["page-notices"],
- revalidate: 3600, // 1시간 캐시
- }
-)
+// 페이지별 공지사항 조회 (직접 호출용)
+export async function getPageNoticesDirect(pagePath: string) {
+ return await getPageNotices(pagePath)
+}
// 공지사항 생성
export async function createNotice(input: CreateNoticeSchema) {
try {
const result = await insertNotice(input)
- revalidateTag("page-notices")
- revalidateTag("notice-lists")
-
return {
success: true,
data: result,
@@ -225,9 +103,6 @@ export async function updateNoticeData(input: UpdateNoticeSchema) { }
}
- revalidateTag("page-notices")
- revalidateTag("notice-lists")
-
return {
success: true,
message: "공지사항이 성공적으로 수정되었습니다."
@@ -253,9 +128,6 @@ export async function deleteNotice(id: number) { }
}
- revalidateTag("page-notices")
- revalidateTag("notice-lists")
-
return {
success: true,
message: "공지사항이 성공적으로 삭제되었습니다."
@@ -274,9 +146,6 @@ export async function deleteMultipleNotices(ids: number[]) { try {
const deletedCount = await deleteNoticeByIds(ids)
- revalidateTag("page-notices")
- revalidateTag("notice-lists")
-
return {
success: true,
deletedCount,
@@ -311,7 +180,7 @@ export async function getPagePathList(): Promise<Array<{ pagePath: string; pageN })
.from(pageInformation)
.where(eq(pageInformation.isActive, true))
- .orderBy(asc(pageInformation.pagePath))
+ .orderBy(desc(pageInformation.pagePath))
return result.map(item => ({
pagePath: item.pagePath,
@@ -349,8 +218,6 @@ export async function syncNoticeFromMenuAssignments() { processedCount++;
}
- revalidateTag("notice");
-
return {
success: true,
message: `공지사항 경로 동기화 확인 완료: ${processedCount}개 확인, ${missingPaths.length}개 누락`,
diff --git a/lib/notice/validations.ts b/lib/notice/validations.ts index 05e84af9..146f8e09 100644 --- a/lib/notice/validations.ts +++ b/lib/notice/validations.ts @@ -1,14 +1,4 @@ import { z } from "zod"
-import {
- createSearchParamsCache,
- parseAsArrayOf,
- parseAsInteger,
- parseAsString,
- parseAsStringEnum,
- parseAsBoolean,
-} from "nuqs/server"
-import { getFiltersStateParser, getSortingStateParser } from "@/lib/parsers"
-import { Notice } from "@/db/schema/notice"
// 공지사항 생성 스키마
export const createNoticeSchema = z.object({
@@ -28,53 +18,12 @@ export const updateNoticeSchema = z.object({ isActive: z.boolean().default(true),
})
-// 현대적인 검색 파라미터 캐시
-export const searchParamsNoticeCache = createSearchParamsCache({
- flags: parseAsArrayOf(z.enum(["advancedTable", "floatingBar"])).withDefault([]),
- page: parseAsInteger.withDefault(1),
- perPage: parseAsInteger.withDefault(10),
- sort: getSortingStateParser<Notice>().withDefault([
- { id: "createdAt", desc: true },
- ]),
-
- // 기본 검색 필드들
- pagePath: parseAsString.withDefault(""),
- title: parseAsString.withDefault(""),
- content: parseAsString.withDefault(""),
- authorId: parseAsInteger,
- isActive: parseAsBoolean,
-
- // 고급 필터
- filters: getFiltersStateParser().withDefault([]),
- joinOperator: parseAsStringEnum(["and", "or"]).withDefault("and"),
- search: parseAsString.withDefault(""),
-
- // 날짜 범위
- from: parseAsString.withDefault(""),
- to: parseAsString.withDefault(""),
-})
-
-// 타입 추출
-export type CreateNoticeSchema = z.infer<typeof createNoticeSchema>
-export type UpdateNoticeSchema = z.infer<typeof updateNoticeSchema>
-export type GetNoticeSchema = Awaited<ReturnType<typeof searchParamsNoticeCache.parse>>
-
-// 기존 스키마 (하위 호환성을 위해 유지)
-export const getNoticeSchema = z.object({
- page: z.coerce.number().default(1),
- per_page: z.coerce.number().default(10),
- sort: z.string().optional(),
- pagePath: z.string().optional(),
- title: z.string().optional(),
- authorId: z.coerce.number().optional(),
- isActive: z.coerce.boolean().optional(),
- from: z.string().optional(),
- to: z.string().optional(),
-})
-
// 페이지 경로별 공지사항 조회 스키마
export const getPageNoticeSchema = z.object({
pagePath: z.string().min(1, "페이지 경로를 입력해주세요"),
})
+// 타입 추출
+export type CreateNoticeSchema = z.infer<typeof createNoticeSchema>
+export type UpdateNoticeSchema = z.infer<typeof updateNoticeSchema>
export type GetPageNoticeSchema = z.infer<typeof getPageNoticeSchema>
\ No newline at end of file diff --git a/lib/vendor-regular-registrations/repository.ts b/lib/vendor-regular-registrations/repository.ts index 38bf4aaf..aec3d275 100644 --- a/lib/vendor-regular-registrations/repository.ts +++ b/lib/vendor-regular-registrations/repository.ts @@ -75,6 +75,8 @@ export async function getVendorRegularRegistrations( status: basicContract.status,
templateName: basicContractTemplates.templateName,
createdAt: basicContract.createdAt,
+ filePath: basicContract.filePath,
+ fileName: basicContract.fileName,
})
.from(basicContract)
.leftJoin(basicContractTemplates, eq(basicContract.templateId, basicContractTemplates.id))
@@ -153,6 +155,35 @@ export async function getVendorRegularRegistrations( auditResult: investigationFiles,
};
+ // 디버깅용 로그 추가
+ console.log(`🔍 벤더 ID ${registration.vendorId} documentFiles 구조:`, {
+ businessRegistration: documentFiles.businessRegistration.map(f => ({
+ fileName: f.fileName,
+ filePath: f.filePath,
+ attachmentType: f.attachmentType,
+ allKeys: Object.keys(f)
+ })),
+ creditEvaluation: documentFiles.creditEvaluation.map(f => ({
+ fileName: f.fileName,
+ filePath: f.filePath,
+ attachmentType: f.attachmentType,
+ allKeys: Object.keys(f)
+ })),
+ bankCopy: documentFiles.bankCopy.map(f => ({
+ fileName: f.fileName,
+ filePath: f.filePath,
+ attachmentType: f.attachmentType,
+ allKeys: Object.keys(f)
+ })),
+ auditResult: documentFiles.auditResult.map(f => ({
+ fileName: f.fileName,
+ attachmentType: f.attachmentType,
+ allKeys: Object.keys(f)
+ })),
+ totalVendorFiles: vendorFiles.length,
+ totalInvestigationFiles: investigationFiles.length
+ });
+
// 문서 제출 현황 로그
console.log(`📊 벤더 ID ${registration.vendorId} 문서 제출 현황:`, {
documentSubmissionsStatus,
@@ -230,11 +261,13 @@ export async function getVendorRegularRegistrations( gtcSkipped: registration.gtcSkipped || false,
additionalInfo: additionalInfoCompleted,
// 기본계약 정보
- basicContracts: vendorContracts.map(contract => ({
+ basicContracts: vendorContracts.map((contract: any) => ({
templateId: contract.templateId,
templateName: contract.templateName,
status: contract.status,
createdAt: contract.createdAt,
+ filePath: contract.filePath,
+ fileName: contract.fileName,
})),
registrationRequestDate: registration.registrationRequestDate || null,
assignedDepartment: registration.assignedDepartment,
diff --git a/lib/vendor-regular-registrations/service.ts b/lib/vendor-regular-registrations/service.ts index d64c7b8b..7ec433b4 100644 --- a/lib/vendor-regular-registrations/service.ts +++ b/lib/vendor-regular-registrations/service.ts @@ -714,6 +714,8 @@ export async function fetchVendorRegistrationStatus(vendorId: number) { const investigationFiles = await db
.select({
attachmentId: vendorInvestigationAttachments.id,
+ fileName: vendorInvestigationAttachments.fileName,
+ filePath: vendorInvestigationAttachments.filePath,
createdAt: vendorInvestigationAttachments.createdAt,
})
.from(vendorInvestigationAttachments)
@@ -735,6 +737,8 @@ export async function fetchVendorRegistrationStatus(vendorId: number) { templateName: basicContractTemplates.templateName,
status: basicContract.status,
createdAt: basicContract.createdAt,
+ filePath: basicContract.filePath,
+ fileName: basicContract.fileName,
})
.from(basicContract)
.leftJoin(basicContractTemplates, eq(basicContract.templateId, basicContractTemplates.id))
@@ -796,6 +800,14 @@ export async function fetchVendorRegistrationStatus(vendorId: number) { safetyQualification: investigationFiles.length > 0,
}
+ // 문서별 파일 정보 (다운로드용)
+ const documentFiles = {
+ businessRegistration: vendorFiles.filter(f => f.attachmentType === "BUSINESS_REGISTRATION"),
+ creditEvaluation: vendorFiles.filter(f => f.attachmentType === "CREDIT_REPORT"),
+ bankCopy: vendorFiles.filter(f => f.attachmentType === "BANK_ACCOUNT_COPY"),
+ auditResult: investigationFiles,
+ }
+
// 미완성 항목 계산
const missingDocuments = Object.entries(documentStatus)
.filter(([, value]) => !value)
@@ -831,6 +843,7 @@ export async function fetchVendorRegistrationStatus(vendorId: number) { vendor: vendor[0],
registration: registration[0] || null,
documentStatus,
+ documentFiles, // 문서별 파일 정보 추가
missingDocuments,
businessContacts,
missingContactTypes,
|
