summaryrefslogtreecommitdiff
path: root/lib/evaluation-target-list/service.ts
diff options
context:
space:
mode:
Diffstat (limited to 'lib/evaluation-target-list/service.ts')
-rw-r--r--lib/evaluation-target-list/service.ts267
1 files changed, 174 insertions, 93 deletions
diff --git a/lib/evaluation-target-list/service.ts b/lib/evaluation-target-list/service.ts
index 1c133e3a..8d890604 100644
--- a/lib/evaluation-target-list/service.ts
+++ b/lib/evaluation-target-list/service.ts
@@ -73,79 +73,63 @@ export async function countEvaluationTargetsFromView(
// ============= 메인 서버 액션도 함께 수정 =============
export async function getEvaluationTargets(input: GetEvaluationTargetsSchema) {
try {
+ console.log("=== 서버 액션 호출 ===");
+ console.log("필터 수:", input.filters?.length || 0);
+ console.log("조인 연산자:", input.joinOperator);
+
const offset = (input.page - 1) * input.perPage;
- // ✅ getRFQ 방식과 동일한 필터링 처리
- // 1) 고급 필터 조건
+ // ✅ 단순화된 필터 처리
let advancedWhere: SQL<unknown> | undefined = undefined;
- if (input.filters && input.filters.length > 0) {
- advancedWhere = filterColumns({
- table: evaluationTargetsWithDepartments,
- filters: input.filters,
- joinOperator: input.joinOperator || 'and',
- });
- }
-
- // 2) 기본 필터 조건
- let basicWhere: SQL<unknown> | undefined = undefined;
- if (input.basicFilters && input.basicFilters.length > 0) {
- basicWhere = filterColumns({
- table: evaluationTargetsWithDepartments,
- filters: input.basicFilters,
- joinOperator: input.basicJoinOperator || 'and',
- });
+
+ if (input.filters && Array.isArray(input.filters) && input.filters.length > 0) {
+ console.log("필터 적용:", input.filters.map(f => `${f.id} ${f.operator} ${f.value}`));
+
+ try {
+ advancedWhere = filterColumns({
+ table: evaluationTargetsWithDepartments,
+ filters: input.filters,
+ joinOperator: input.joinOperator || 'and',
+ });
+
+ console.log("필터 조건 생성 완료");
+ } catch (error) {
+ console.error("필터 조건 생성 오류:", error);
+ // 필터 오류 시에도 전체 데이터 반환
+ advancedWhere = undefined;
+ }
}
- // 3) 글로벌 검색 조건
+ // 2) 글로벌 검색 조건
let globalWhere: SQL<unknown> | undefined = undefined;
if (input.search) {
const s = `%${input.search}%`;
- const validSearchConditions: SQL<unknown>[] = [];
-
- const vendorCodeCondition = ilike(evaluationTargetsWithDepartments.vendorCode, s);
- if (vendorCodeCondition) validSearchConditions.push(vendorCodeCondition);
-
- const vendorNameCondition = ilike(evaluationTargetsWithDepartments.vendorName, s);
- if (vendorNameCondition) validSearchConditions.push(vendorNameCondition);
-
- const adminCommentCondition = ilike(evaluationTargetsWithDepartments.adminComment, s);
- if (adminCommentCondition) validSearchConditions.push(adminCommentCondition);
-
- const consolidatedCommentCondition = ilike(evaluationTargetsWithDepartments.consolidatedComment, s);
- if (consolidatedCommentCondition) validSearchConditions.push(consolidatedCommentCondition);
-
- // 담당자 이름으로도 검색
- const orderReviewerCondition = ilike(evaluationTargetsWithDepartments.orderReviewerName, s);
- if (orderReviewerCondition) validSearchConditions.push(orderReviewerCondition);
-
- const procurementReviewerCondition = ilike(evaluationTargetsWithDepartments.procurementReviewerName, s);
- if (procurementReviewerCondition) validSearchConditions.push(procurementReviewerCondition);
-
- const qualityReviewerCondition = ilike(evaluationTargetsWithDepartments.qualityReviewerName, s);
- if (qualityReviewerCondition) validSearchConditions.push(qualityReviewerCondition);
-
- const designReviewerCondition = ilike(evaluationTargetsWithDepartments.designReviewerName, s);
- if (designReviewerCondition) validSearchConditions.push(designReviewerCondition);
-
- const csReviewerCondition = ilike(evaluationTargetsWithDepartments.csReviewerName, s);
- if (csReviewerCondition) validSearchConditions.push(csReviewerCondition);
-
- if (validSearchConditions.length > 0) {
- globalWhere = or(...validSearchConditions);
+ const searchConditions: SQL<unknown>[] = [
+ ilike(evaluationTargetsWithDepartments.vendorCode, s),
+ ilike(evaluationTargetsWithDepartments.vendorName, s),
+ ilike(evaluationTargetsWithDepartments.adminComment, s),
+ ilike(evaluationTargetsWithDepartments.consolidatedComment, s),
+ ilike(evaluationTargetsWithDepartments.orderReviewerName, s),
+ ilike(evaluationTargetsWithDepartments.procurementReviewerName, s),
+ ilike(evaluationTargetsWithDepartments.qualityReviewerName, s),
+ ilike(evaluationTargetsWithDepartments.designReviewerName, s),
+ ilike(evaluationTargetsWithDepartments.csReviewerName, s),
+ ].filter(Boolean);
+
+ if (searchConditions.length > 0) {
+ globalWhere = or(...searchConditions);
}
}
- // ✅ getRFQ 방식과 동일한 WHERE 조건 생성
+ // 3) 최종 WHERE 조건 결합
const whereConditions: SQL<unknown>[] = [];
-
if (advancedWhere) whereConditions.push(advancedWhere);
- if (basicWhere) whereConditions.push(basicWhere);
if (globalWhere) whereConditions.push(globalWhere);
const finalWhere = whereConditions.length > 0 ? and(...whereConditions) : undefined;
- // ✅ getRFQ 방식과 동일한 전체 데이터 수 조회 (Transaction 제거)
+ // 4) 전체 데이터 수 조회
const totalResult = await db
.select({ count: count() })
.from(evaluationTargetsWithDepartments)
@@ -157,12 +141,14 @@ export async function getEvaluationTargets(input: GetEvaluationTargetsSchema) {
return { data: [], pageCount: 0, total: 0 };
}
- console.log("Total evaluation targets:", total);
+ console.log("총 데이터 수:", total);
- // ✅ getRFQ 방식과 동일한 정렬 및 페이징 처리된 데이터 조회
+ // 5) 정렬 및 페이징 처리
const orderByColumns = input.sort.map((sort) => {
const column = sort.id as keyof typeof evaluationTargetsWithDepartments.$inferSelect;
- return sort.desc ? desc(evaluationTargetsWithDepartments[column]) : asc(evaluationTargetsWithDepartments[column]);
+ return sort.desc
+ ? desc(evaluationTargetsWithDepartments[column])
+ : asc(evaluationTargetsWithDepartments[column]);
});
if (orderByColumns.length === 0) {
@@ -179,10 +165,11 @@ export async function getEvaluationTargets(input: GetEvaluationTargetsSchema) {
const pageCount = Math.ceil(total / input.perPage);
+ console.log("반환 데이터 수:", evaluationData.length);
+
return { data: evaluationData, pageCount, total };
} catch (err) {
- console.error("Error in getEvaluationTargets:", err);
- // ✅ getRFQ 방식과 동일한 에러 반환 (total 포함)
+ console.error("getEvaluationTargets 오류:", err);
return { data: [], pageCount: 0, total: 0 };
}
}
@@ -440,8 +427,6 @@ export interface UpdateEvaluationTargetInput {
}
export async function updateEvaluationTarget(input: UpdateEvaluationTargetInput) {
- console.log(input, "update input")
-
try {
const session = await getServerSession(authOptions)
@@ -542,8 +527,8 @@ export async function updateEvaluationTarget(input: UpdateEvaluationTargetInput)
{ departmentCode: EVALUATION_DEPARTMENT_CODES.ORDER_EVAL, isApproved: input.orderIsApproved },
{ departmentCode: EVALUATION_DEPARTMENT_CODES.PROCUREMENT_EVAL, isApproved: input.procurementIsApproved },
{ departmentCode: EVALUATION_DEPARTMENT_CODES.QUALITY_EVAL, isApproved: input.qualityIsApproved },
- { departmentCode: EVALUATION_DEPARTMENT_CODES.DESIGN_EVAL, isApproved: input.designIsApproved },
- { departmentCode: EVALUATION_DEPARTMENT_CODES.CS_EVAL, isApproved: input.csIsApproved },
+ // { departmentCode: EVALUATION_DEPARTMENT_CODES.DESIGN_EVAL, isApproved: input.designIsApproved },
+ // { departmentCode: EVALUATION_DEPARTMENT_CODES.CS_EVAL, isApproved: input.csIsApproved },
]
for (const review of reviewUpdates) {
@@ -589,46 +574,43 @@ export async function updateEvaluationTarget(input: UpdateEvaluationTargetInput)
}
}
- // 4. 의견 일치 상태 및 전체 상태 자동 계산
+ const requiredDepartments = [
+ EVALUATION_DEPARTMENT_CODES.ORDER_EVAL,
+ EVALUATION_DEPARTMENT_CODES.PROCUREMENT_EVAL,
+ EVALUATION_DEPARTMENT_CODES.QUALITY_EVAL
+ ]
+
const currentReviews = await tx
.select({
isApproved: evaluationTargetReviews.isApproved,
departmentCode: evaluationTargetReviews.departmentCode,
})
.from(evaluationTargetReviews)
- .where(eq(evaluationTargetReviews.evaluationTargetId, input.id))
-
-
- const evaluationTargetForConcensus = await tx
- .select({
- materialType: evaluationTargets.materialType,
- })
- .from(evaluationTargets)
- .where(eq(evaluationTargets.id, input.id))
- .limit(1)
-
- if (evaluationTargetForConcensus.length === 0) {
- throw new Error("평가 대상을 찾을 수 없습니다.")
- }
-
- const { materialType } = evaluationTargetForConcensus[0]
- const minimumReviewsRequired = materialType === "BULK" ? 3 : 5
+ .where(
+ and(
+ eq(evaluationTargetReviews.evaluationTargetId, input.id),
+ inArray(evaluationTargetReviews.departmentCode, requiredDepartments)
+ )
+ )
+ // 3개 필수 부서의 리뷰가 모두 완료된 경우에만 의견 일치 상태 계산
+ const reviewedDepartments = currentReviews.map(r => r.departmentCode)
+ const allRequiredDepartmentsReviewed = requiredDepartments.every(dept =>
+ reviewedDepartments.includes(dept)
+ )
- // 최소 3개 부서에서 평가가 완료된 경우 의견 일치 상태 계산
- if (currentReviews.length >= minimumReviewsRequired) {
+ if (allRequiredDepartmentsReviewed) {
const approvals = currentReviews.map(r => r.isApproved)
const allApproved = approvals.every(approval => approval === true)
const allRejected = approvals.every(approval => approval === false)
const hasConsensus = allApproved || allRejected
- // let newStatus: "PENDING" | "CONFIRMED" | "EXCLUDED" = "PENDING"
- // if (hasConsensus) {
- // newStatus = allApproved ? "CONFIRMED" : "EXCLUDED"
- // }
-
- // console.log("Auto-updating status:", { hasConsensus, newStatus, approvals })
- console.log("Auto-updating status:", { hasConsensus, approvals })
+ console.log("Auto-updating consensus status:", {
+ hasConsensus,
+ approvals,
+ reviewedDepartments,
+ allRequiredDepartmentsReviewed
+ })
await tx
.update(evaluationTargets)
@@ -954,7 +936,7 @@ export async function confirmEvaluationTargets(
return {
success: true,
- message: `${result.totalConfirmed}개 평가 대상이 확정되었습니다. ${result.createdEvaluationsCount}개의 정기평가와 ${result.createdSubmissionsCount}개의 제출 요청이 생성되었습니다.`,
+ message: `${result.totalConfirmed}개 평가 대상이 확정되었습니다. ${result.createdEvaluationsCount}개의 정기평가가 생성되었습니다.`,
confirmedCount: result.totalConfirmed,
createdEvaluationsCount: result.createdEvaluationsCount,
// createdSubmissionsCount: result.createdSubmissionsCount
@@ -1377,4 +1359,103 @@ export async function autoGenerateEvaluationTargets(
message: "평가 대상 자동 생성에 실패했습니다."
}
}
-} \ No newline at end of file
+}
+
+
+export async function deleteEvaluationTargets(targetIds: number[]) {
+ console.log(targetIds, "targetIds to delete");
+
+ try {
+ const session = await getServerSession(authOptions);
+
+ if (!session?.user?.id) {
+ throw new Error("로그인이 필요합니다.");
+ }
+
+ // 권한 체크 (필요한 경우)
+ // const hasPermission = await checkUserPermission(session.user.id, 'manage_evaluations');
+ // if (!hasPermission) {
+ // throw new Error("평가 관리 권한이 없습니다.");
+ // }
+
+ return await db.transaction(async (tx) => {
+ // 1. 삭제하려는 타겟들이 존재하고 PENDING 상태인지 확인
+ const targetsToDelete = await tx
+ .select({
+ id: evaluationTargets.id,
+ status: evaluationTargets.status,
+ vendorName: evaluationTargets.vendorName,
+ evaluationYear: evaluationTargets.evaluationYear,
+ division: evaluationTargets.division,
+ })
+ .from(evaluationTargets)
+ .where(inArray(evaluationTargets.id, targetIds));
+
+ if (targetsToDelete.length === 0) {
+ throw new Error("삭제할 평가 대상을 찾을 수 없습니다.");
+ }
+
+ // PENDING 상태가 아닌 타겟들 확인
+ const nonPendingTargets = targetsToDelete.filter(target => target.status !== 'PENDING');
+ if (nonPendingTargets.length > 0) {
+ const nonPendingNames = nonPendingTargets
+ .map(t => `${t.vendorName} (${t.evaluationYear}년)`)
+ .join(', ');
+ throw new Error(`다음 평가 대상은 PENDING 상태가 아니어서 삭제할 수 없습니다: ${nonPendingNames}`);
+ }
+
+ // 실제로 삭제할 수 있는 타겟 ID들
+ const validTargetIds = targetsToDelete.map(t => t.id);
+
+ console.log(`Deleting ${validTargetIds.length} evaluation targets:`,
+ targetsToDelete.map(t => `${t.vendorName} (${t.evaluationYear}년, ${t.division})`));
+
+ // 2. 관련된 자식 테이블들 먼저 삭제
+ // evaluationTargetReviewers 테이블 삭제
+ const deletedReviewers = await tx
+ .delete(evaluationTargetReviewers)
+ .where(inArray(evaluationTargetReviewers.evaluationTargetId, validTargetIds))
+ .returning({ id: evaluationTargetReviewers.id });
+
+ console.log(`Deleted ${deletedReviewers.length} reviewer assignments`);
+
+ // 3. 기타 관련 테이블들 삭제 (필요한 경우 추가)
+ // 예: evaluationTargetDepartments, evaluationComments 등
+ // const deletedDepartments = await tx
+ // .delete(evaluationTargetDepartments)
+ // .where(inArray(evaluationTargetDepartments.evaluationTargetId, validTargetIds))
+ // .returning({ id: evaluationTargetDepartments.id });
+
+ // 4. 메인 테이블 삭제
+ const deletedTargets = await tx
+ .delete(evaluationTargets)
+ .where(inArray(evaluationTargets.id, validTargetIds))
+ .returning({
+ id: evaluationTargets.id,
+ vendorName: evaluationTargets.vendorName,
+ evaluationYear: evaluationTargets.evaluationYear
+ });
+
+ console.log(`Successfully deleted ${deletedTargets.length} evaluation targets`);
+
+ return {
+ success: true,
+ deletedCount: deletedTargets.length,
+ deletedTargets: deletedTargets.map(t => ({
+ id: t.id,
+ vendorName: t.vendorName,
+ evaluationYear: t.evaluationYear
+ })),
+ message: `${deletedTargets.length}개의 평가 대상이 성공적으로 삭제되었습니다.`,
+ };
+ });
+
+ } catch (error) {
+ console.error("Error deleting evaluation targets:", error);
+ return {
+ success: false,
+ error: error instanceof Error ? error.message : "평가 대상 삭제 중 오류가 발생했습니다.",
+ };
+ }
+}
+