diff options
Diffstat (limited to 'lib/vendor-document-list')
6 files changed, 109 insertions, 106 deletions
diff --git a/lib/vendor-document-list/enhanced-document-service.ts b/lib/vendor-document-list/enhanced-document-service.ts index d2cec15d..05ace8d5 100644 --- a/lib/vendor-document-list/enhanced-document-service.ts +++ b/lib/vendor-document-list/enhanced-document-service.ts @@ -4,7 +4,7 @@ import { revalidatePath, unstable_cache } from "next/cache" import { and, asc, desc, eq, ilike, or, count, avg, inArray, sql } from "drizzle-orm" import db from "@/db/db" -import { documentAttachments, documentStagesOnlyView, documents, enhancedDocumentsView, issueStages, revisions, simplifiedDocumentsView, type EnhancedDocumentsView } from "@/db/schema/vendorDocu" +import { StageDocumentsView, documentAttachments, documentStagesOnlyView, documents, enhancedDocumentsView, issueStages, revisions, simplifiedDocumentsView, type EnhancedDocumentsView } from "@/db/schema/vendorDocu" import { filterColumns } from "@/lib/filter-columns" import type { CreateDocumentInput, @@ -42,6 +42,22 @@ export interface GetEnhancedDocumentsSchema { }> } +export interface GetDocumentsSchema { + page: number + perPage: number + search?: string + filters?: Array<{ + id: string + value: string | string[] + operator?: "eq" | "ne" | "like" | "ilike" | "in" | "notin" | "lt" | "lte" | "gt" | "gte" + }> + joinOperator?: "and" | "or" + sort?: Array<{ + id: keyof StageDocumentsView + desc: boolean + }> +} + // Repository 함수들 export async function selectEnhancedDocuments( tx: any, @@ -1024,19 +1040,7 @@ export async function getDocumentDetails(documentId: number) { if (!companyId) { return { data: [], pageCount: 0, total: 0, drawingKind: null, vendorInfo: null } } - - // 2. 해당 벤더의 모든 계약 ID들 조회 - const vendorContracts = await db - .select({ projectId: contracts.projectId, contractId:contracts.id }) - .from(contracts) - .where(eq(contracts.vendorId, companyId)) - - const contractIds = vendorContracts.map(c => c.contractId) - - if (contractIds.length === 0) { - return { data: [], pageCount: 0, total: 0, drawingKind: null, vendorInfo: null } - } - + // 3. 고급 필터 처리 const advancedWhere = filterColumns({ table: simplifiedDocumentsView, @@ -1057,7 +1061,7 @@ export async function getDocumentDetails(documentId: number) { // 5. 최종 WHERE 조건 (계약 ID들로 필터링) const finalWhere = and( - inArray(simplifiedDocumentsView.contractId, contractIds), + eq(simplifiedDocumentsView.vendorId, Number(companyId)), advancedWhere, globalWhere, ) @@ -1133,32 +1137,18 @@ export async function getDocumentDetails(documentId: number) { } const companyId = session?.user?.companyId; - if (!companyId) { return { stats: {}, totalDocuments: 0, primaryDrawingKind: null } } - - // 해당 벤더의 계약 ID들 조회 - const vendorContracts = await db - .select({ id: contracts.id }) - .from(contracts) - .where(eq(contracts.vendorId, companyId)) - - const contractIds = vendorContracts.map(c => c.id) - - if (contractIds.length === 0) { - return { stats: {}, totalDocuments: 0, primaryDrawingKind: null } - } - + // DrawingKind별 통계 조회 const documents = await db .select({ drawingKind: simplifiedDocumentsView.drawingKind, - contractId: simplifiedDocumentsView.contractId, }) .from(simplifiedDocumentsView) - .where(inArray(simplifiedDocumentsView.contractId, contractIds)) + .where(eq(simplifiedDocumentsView.vendorId, Number(companyId))) // 통계 계산 const stats = documents.reduce((acc, doc) => { diff --git a/lib/vendor-document-list/import-service.ts b/lib/vendor-document-list/import-service.ts index 84e4263c..216e373e 100644 --- a/lib/vendor-document-list/import-service.ts +++ b/lib/vendor-document-list/import-service.ts @@ -9,6 +9,8 @@ import { v4 as uuidv4 } from "uuid" import { extname } from "path" import * as crypto from "crypto" import { debugError, debugWarn, debugSuccess, debugProcess } from "@/lib/debug-utils" +import { getServerSession } from "next-auth/next" +import { authOptions } from "@/app/api/auth/[...nextauth]/route" export interface ImportResult { success: boolean @@ -155,11 +157,11 @@ class ImportService { throw new Error(`Project code or vendor code not found for contract ${projectId}`) } - debugLog(`계약 정보 조회 완료`, { - projectId, - projectCode: contractInfo.projectCode, - vendorCode: contractInfo.vendorCode - }) + // debugLog(`계약 정보 조회 완료`, { + // projectId, + // projectCode: contractInfo.projectCode, + // vendorCode: contractInfo.vendorCode + // }) // 2. 각 drawingKind별로 데이터 조회 const allDocuments: DOLCEDocument[] = [] @@ -324,6 +326,13 @@ class ImportService { projectCode: string; vendorCode: string; } | null> { + + const session = await getServerSession(authOptions) + if (!session?.user?.companyId) { + throw new Error("인증이 필요합니다.") + } + + const [result] = await db .select({ projectCode: projects.code, @@ -332,7 +341,7 @@ class ImportService { .from(contracts) .innerJoin(projects, eq(contracts.projectId, projects.id)) .innerJoin(vendors, eq(contracts.vendorId, vendors.id)) - .where(eq(contracts.projectId, projectId)) + .where(and(eq(contracts.projectId, projectId),eq(contracts.vendorId, Number(session.user.companyId)))) .limit(1) return result?.projectCode && result?.vendorCode @@ -633,6 +642,15 @@ class ImportService { dolceDoc: DOLCEDocument, sourceSystem: string ): Promise<'NEW' | 'UPDATED' | 'SKIPPED'> { + + const session = await getServerSession(authOptions) + if (!session?.user?.companyId) { + throw new Error("인증이 필요합니다.") + } + + const vendorId = Number(session.user.companyId) + + // 기존 문서 조회 (문서 번호로) const existingDoc = await db .select() @@ -646,6 +664,7 @@ class ImportService { // DOLCE 문서를 DB 스키마에 맞게 변환 const documentData = { projectId, + vendorId, docNumber: dolceDoc.DrawingNo, title: dolceDoc.DrawingName, status: 'ACTIVE', diff --git a/lib/vendor-document-list/plant/document-stage-validations.ts b/lib/vendor-document-list/plant/document-stage-validations.ts index 037293e3..434459a7 100644 --- a/lib/vendor-document-list/plant/document-stage-validations.ts +++ b/lib/vendor-document-list/plant/document-stage-validations.ts @@ -8,7 +8,7 @@ import { parseAsStringEnum, } from "nuqs/server" import { getFiltersStateParser, getSortingStateParser } from "@/lib/parsers" -import { DocumentStagesOnlyView } from "@/db/schema" +import { DocumentStagesOnlyView, StageDocumentsView } from "@/db/schema" // ============================================================================= // 1. 문서 관련 스키마들 @@ -153,7 +153,7 @@ export const searchParamsSchema = z.object({ export const documentStageSearchParamsCache = createSearchParamsCache({ page: parseAsInteger.withDefault(1), perPage: parseAsInteger.withDefault(10), - sort: getSortingStateParser<DocumentStagesOnlyView>().withDefault([ + sort: getSortingStateParser<StageDocumentsView>().withDefault([ { id: "createdAt", desc: true }, ]), @@ -161,15 +161,6 @@ export const documentStageSearchParamsCache = createSearchParamsCache({ filters: getFiltersStateParser().withDefault([]), joinOperator: parseAsStringEnum(["and", "or"]).withDefault("and"), search: parseAsString.withDefault(""), - - // 문서 스테이지 전용 필터들 - drawingKind: parseAsStringEnum(["all", "B3", "B4", "B5"]).withDefault("all"), - stageStatus: parseAsStringEnum(["all", "PLANNED", "IN_PROGRESS", "SUBMITTED", "APPROVED", "REJECTED", "COMPLETED"]).withDefault("all"), - priority: parseAsStringEnum(["all", "HIGH", "MEDIUM", "LOW"]).withDefault("all"), - isOverdue: parseAsStringEnum(["all", "true", "false"]).withDefault("all"), - assignee: parseAsString.withDefault(""), - dateFrom: parseAsString.withDefault(""), - dateTo: parseAsString.withDefault(""), }) // ============================================================================= diff --git a/lib/vendor-document-list/plant/document-stages-columns.tsx b/lib/vendor-document-list/plant/document-stages-columns.tsx index 7456c2aa..742b8a8a 100644 --- a/lib/vendor-document-list/plant/document-stages-columns.tsx +++ b/lib/vendor-document-list/plant/document-stages-columns.tsx @@ -272,22 +272,22 @@ export function getDocumentStagesColumns({ ), cell: ({ row }) => { const doc = row.original - if (!doc.currentStageName) { - return ( - <Button - size="sm" - variant="outline" - onClick={(e) => { - e.stopPropagation() - setRowAction({ row, type: "add_stage" }) - }} - className="h-6 text-xs" - > - <Plus className="w-3 h-3 mr-1" /> - Add stage - </Button> - ) - } + // if (!doc.currentStageName) { + // return ( + // <Button + // size="sm" + // variant="outline" + // onClick={(e) => { + // e.stopPropagation() + // setRowAction({ row, type: "add_stage" }) + // }} + // className="h-6 text-xs" + // > + // <Plus className="w-3 h-3 mr-1" /> + // Add stage + // </Button> + // ) + // } return ( <div className="flex items-center gap-2"> diff --git a/lib/vendor-document-list/plant/document-stages-service.ts b/lib/vendor-document-list/plant/document-stages-service.ts index 1e60a062..c6a891c8 100644 --- a/lib/vendor-document-list/plant/document-stages-service.ts +++ b/lib/vendor-document-list/plant/document-stages-service.ts @@ -4,7 +4,7 @@ import { revalidatePath, revalidateTag } from "next/cache" import { redirect } from "next/navigation" import db from "@/db/db" -import { codeGroups, comboBoxSettings, contracts, documentClassOptions, documentClasses, documentNumberTypeConfigs, documentNumberTypes, documentStagesOnlyView, documents, issueStages } from "@/db/schema" +import { codeGroups, comboBoxSettings, contracts, documentClassOptions, documentClasses, documentNumberTypeConfigs, documentNumberTypes, documentStagesOnlyView, documents, issueStages, stageDocuments, stageDocumentsView, stageIssueStages } from "@/db/schema" import { and, eq, asc, desc, sql, inArray, max, ne, or, ilike } from "drizzle-orm" import { createDocumentSchema, @@ -28,7 +28,7 @@ import { } from "./document-stage-validations" import { unstable_noStore as noStore } from "next/cache" import { filterColumns } from "@/lib/filter-columns" -import { GetEnhancedDocumentsSchema } from "../enhanced-document-service" +import { GetEnhancedDocumentsSchema, GetDocumentsSchema } from "../enhanced-document-service" import { countDocumentStagesOnly, selectDocumentStagesOnly } from "../repository" interface UpdateDocumentData { @@ -914,21 +914,20 @@ export async function createDocument(data: CreateDocumentData) { columns: { id: true, projectId: true, + vendorId: true, }, }) if (!contract) { return { success: false, error: "유효하지 않은 계약(ID)입니다." } } - const { projectId } = contract + const { projectId, vendorId } = contract /* ──────────────────────────────── 1. 문서번호 타입 설정 조회 ─────────────────────────────── */ const configsResult = await getDocumentNumberTypeConfigs( data.documentNumberTypeId ) - console.log(configsResult, "configsResult") - if (!configsResult.success) { return { success: false, error: configsResult.error } } @@ -937,7 +936,8 @@ export async function createDocument(data: CreateDocumentData) { /* ──────────────────────────────── 3. 문서 레코드 삽입 ─────────────────────────────── */ const insertData = { // 필수 - projectId, // ★ 새로 추가 + projectId, + vendorId, // ★ 새로 추가 contractId: data.contractId, docNumber: data.docNumber, title: data.title, @@ -946,20 +946,19 @@ export async function createDocument(data: CreateDocumentData) { updatedAt: new Date(), // 선택 - pic: data.pic ?? null, - vendorDocNumber: data.vendorDocNumber ?? null, + vendorDocNumber: data.vendorDocNumber === null || data.vendorDocNumber ==='' ? null: data.vendorDocNumber , } const [document] = await db - .insert(documents) + .insert(stageDocuments) .values(insertData) .onConflictDoNothing({ // ★ 유니크 키가 projectId 기반이라면 target 도 같이 변경 target: [ - documents.projectId, - documents.docNumber, - documents.status, + stageDocuments.projectId, + stageDocuments.docNumber, + stageDocuments.status, ], }) .returning() @@ -975,22 +974,27 @@ export async function createDocument(data: CreateDocumentData) { const stageOptionsResult = await getDocumentClassOptions( data.documentClassId ) + + + console.log(data.documentClassId,"documentClassId") + console.log(stageOptionsResult.data) + if (stageOptionsResult.success && stageOptionsResult.data.length > 0) { const now = new Date() const stageInserts = stageOptionsResult.data.map((opt, idx) => ({ documentId: document.id, - stageName: opt.optionValue, + stageName: opt.optionCode, stageOrder: opt.sortOrder ?? idx + 1, stageStatus: "PLANNED" as const, planDate: data.planDates[opt.id] ?? null, createdAt: now, updatedAt: now, })) - await db.insert(issueStages).values(stageInserts) + await db.insert(stageIssueStages).values(stageInserts) } /* ──────────────────────────────── 5. 캐시 무효화 및 응답 ─────────────────────────────── */ - revalidatePath(`/contracts/${data.contractId}/documents`) + revalidatePath(`/partners/${data.contractId}/document-list-only`) return { success: true, @@ -1004,7 +1008,7 @@ export async function createDocument(data: CreateDocumentData) { export async function getDocumentStagesOnly( - input: GetEnhancedDocumentsSchema, + input: GetDocumentsSchema, contractId: number ) { try { @@ -1012,7 +1016,7 @@ export async function getDocumentStagesOnly( // 고급 필터 처리 const advancedWhere = filterColumns({ - table: documentStagesOnlyView, + table: stageDocumentsView, filters: input.filters || [], joinOperator: input.joinOperator || "and", }) @@ -1022,12 +1026,11 @@ export async function getDocumentStagesOnly( if (input.search) { const searchTerm = `%${input.search}%` globalWhere = or( - ilike(documentStagesOnlyView.title, searchTerm), - ilike(documentStagesOnlyView.docNumber, searchTerm), - ilike(documentStagesOnlyView.currentStageName, searchTerm), - ilike(documentStagesOnlyView.currentStageAssigneeName, searchTerm), - ilike(documentStagesOnlyView.vendorDocNumber, searchTerm), - ilike(documentStagesOnlyView.pic, searchTerm) + ilike(stageDocumentsView.title, searchTerm), + ilike(stageDocumentsView.docNumber, searchTerm), + ilike(stageDocumentsView.currentStageName, searchTerm), + ilike(stageDocumentsView.currentStageAssigneeName, searchTerm), + ilike(stageDocumentsView.vendorDocNumber, searchTerm), ) } @@ -1035,17 +1038,17 @@ export async function getDocumentStagesOnly( const finalWhere = and( advancedWhere, globalWhere, - eq(documentStagesOnlyView.contractId, contractId) + eq(stageDocumentsView.contractId, contractId) ) // 정렬 처리 const orderBy = input.sort && input.sort.length > 0 ? input.sort.map((item) => item.desc - ? desc(documentStagesOnlyView[item.id]) - : asc(documentStagesOnlyView[item.id]) + ? desc(stageDocumentsView[item.id]) + : asc(stageDocumentsView[item.id]) ) - : [desc(documentStagesOnlyView.createdAt)] + : [desc(stageDocumentsView.createdAt)] // 트랜잭션 실행 const { data, total } = await db.transaction(async (tx) => { @@ -1075,8 +1078,8 @@ export async function getDocumentStagesOnlyById(documentId: number) { try { const result = await db .select() - .from(documentStagesOnlyView) - .where(eq(documentStagesOnlyView.documentId, documentId)) + .from(stageDocumentsView) + .where(eq(stageDocumentsView.documentId, documentId)) .limit(1) return result[0] || null @@ -1091,8 +1094,8 @@ export async function getDocumentStagesOnlyCount(contractId: number) { try { const result = await db .select({ count: sql<number>`count(*)` }) - .from(documentStagesOnlyView) - .where(eq(documentStagesOnlyView.contractId, contractId)) + .from(stageDocumentsView) + .where(eq(stageDocumentsView.contractId, contractId)) return result[0]?.count ?? 0 } catch (err) { @@ -1113,8 +1116,8 @@ export async function getDocumentProgressStats(contractId: number) { overdueDocuments: sql<number>`count(case when is_overdue = true then 1 end)`, avgProgress: sql<number>`round(avg(progress_percentage), 2)`, }) - .from(documentStagesOnlyView) - .where(eq(documentStagesOnlyView.contractId, contractId)) + .from(stageDocumentsView) + .where(eq(stageDocumentsView.contractId, contractId)) return result[0] || { totalDocuments: 0, @@ -1142,16 +1145,16 @@ export async function getDocumentsByStageStats(contractId: number) { try { const result = await db .select({ - stageName: documentStagesOnlyView.currentStageName, - stageStatus: documentStagesOnlyView.currentStageStatus, + stageName: stageDocumentsView.currentStageName, + stageStatus: stageDocumentsView.currentStageStatus, documentCount: sql<number>`count(*)`, overdueCount: sql<number>`count(case when is_overdue = true then 1 end)`, }) - .from(documentStagesOnlyView) - .where(eq(documentStagesOnlyView.contractId, contractId)) + .from(stageDocumentsView) + .where(eq(stageDocumentsView.contractId, contractId)) .groupBy( - documentStagesOnlyView.currentStageName, - documentStagesOnlyView.currentStageStatus + stageDocumentsView.currentStageName, + stageDocumentsView.currentStageStatus ) .orderBy(sql`count(*) desc`) diff --git a/lib/vendor-document-list/repository.ts b/lib/vendor-document-list/repository.ts index 4eab3853..ab47f013 100644 --- a/lib/vendor-document-list/repository.ts +++ b/lib/vendor-document-list/repository.ts @@ -1,5 +1,5 @@ import db from "@/db/db"; -import { documentStagesOnlyView, documentStagesView } from "@/db/schema/vendorDocu"; +import { stageDocumentsView, documentStagesView } from "@/db/schema/vendorDocu"; import { eq, inArray, @@ -58,7 +58,7 @@ export async function selectDocumentStagesOnly( return tx .select() - .from(documentStagesOnlyView) + .from(stageDocumentsView) .where(where) .orderBy(...(orderBy ?? [])) .offset(offset) @@ -70,7 +70,7 @@ export async function countDocumentStagesOnly( tx: PgTransaction<any, any, any>, where?: any ) { - const res = await tx.select({ count: count() }).from(documentStagesOnlyView).where(where); + const res = await tx.select({ count: count() }).from(stageDocumentsView).where(where); return res[0]?.count ?? 0; } |
