summaryrefslogtreecommitdiff
path: root/lib/basic-contract/agreement-comments/actions.ts
diff options
context:
space:
mode:
authordujinkim <dujin.kim@dtsolution.co.kr>2025-11-21 09:44:33 +0000
committerdujinkim <dujin.kim@dtsolution.co.kr>2025-11-21 09:44:33 +0000
commita2e0785c8749c4d3766ecf3b70edfb7c2fe4df20 (patch)
tree4b03bbec838baf307b38e0c5692da8da7bde2f9b /lib/basic-contract/agreement-comments/actions.ts
parent204fbfb126daf057a4567f64cfb7ab03a5679e82 (diff)
(임수민) 준법 Red Flag 해제, 코멘트 수정
Diffstat (limited to 'lib/basic-contract/agreement-comments/actions.ts')
-rw-r--r--lib/basic-contract/agreement-comments/actions.ts76
1 files changed, 73 insertions, 3 deletions
diff --git a/lib/basic-contract/agreement-comments/actions.ts b/lib/basic-contract/agreement-comments/actions.ts
index c4ded36e..2f60c3d8 100644
--- a/lib/basic-contract/agreement-comments/actions.ts
+++ b/lib/basic-contract/agreement-comments/actions.ts
@@ -2,7 +2,7 @@
import { revalidateTag } from "next/cache";
import db from "@/db/db";
-import { eq, and, desc } from "drizzle-orm";
+import { eq, and, desc, inArray, sql } from "drizzle-orm";
import { agreementComments, basicContract, vendors, users } from "@/db/schema";
import { saveFile, deleteFile } from "@/lib/file-stroage";
import { sendEmail } from "@/lib/mail/sendEmail";
@@ -32,6 +32,23 @@ export interface AgreementCommentData {
updatedAt: Date;
}
+export interface AgreementCommentSummary {
+ hasComments: boolean;
+ commentCount: number;
+}
+
+function getContractDocumentLabel(templateName?: string | null) {
+ if (!templateName) return "기본계약서";
+ const normalized = templateName.toLowerCase();
+ if (normalized.includes('준법')) {
+ return "준법서약";
+ }
+ if (normalized.includes('gtc')) {
+ return "GTC 기본계약서";
+ }
+ return templateName;
+}
+
/**
* 특정 기본계약서의 모든 코멘트 조회
*/
@@ -496,6 +513,55 @@ export async function checkNegotiationStatus(
}
/**
+ * 다수의 계약서에 대한 협의 코멘트 상태 조회
+ */
+export async function checkAgreementCommentsForContracts(
+ contracts: { id: number }[]
+): Promise<Record<number, AgreementCommentSummary>> {
+ if (!contracts || contracts.length === 0) {
+ return {};
+ }
+
+ try {
+ const contractIds = contracts.map(contract => contract.id);
+
+ const commentCounts = await db
+ .select({
+ contractId: agreementComments.basicContractId,
+ count: sql<number>`count(*)`,
+ })
+ .from(agreementComments)
+ .where(
+ and(
+ inArray(agreementComments.basicContractId, contractIds),
+ eq(agreementComments.isDeleted, false)
+ )
+ )
+ .groupBy(agreementComments.basicContractId);
+
+ const countsMap = new Map<number, number>();
+ commentCounts.forEach(({ contractId, count }) => {
+ countsMap.set(contractId, Number(count || 0));
+ });
+
+ const result: Record<number, AgreementCommentSummary> = {};
+
+ contractIds.forEach((contractId) => {
+ const count = countsMap.get(contractId) ?? 0;
+ result[contractId] = {
+ hasComments: count > 0,
+ commentCount: count,
+ };
+ });
+
+ return result;
+ } catch (error) {
+ console.error("협의 상태 조회 실패:", error);
+ return {};
+ }
+}
+
+/**
* 이메일 알림 발송
*/
async function sendCommentNotificationEmail(params: {
@@ -509,6 +575,7 @@ async function sendCommentNotificationEmail(params: {
attachmentCount?: number;
}) {
const { comment, contract, vendor, requester, templateName, authorType, authorName, attachmentCount = 0 } = params;
+ const documentTypeLabel = getContractDocumentLabel(templateName);
// 수신자 결정
let recipientEmail: string | undefined;
@@ -536,7 +603,7 @@ async function sendCommentNotificationEmail(params: {
// 이메일 발송
await sendEmail({
to: recipientEmail,
- subject: `[eVCP] GTC 기본계약서 협의 코멘트 제출 - ${templateName || '기본계약서'}`,
+ subject: `[eVCP] ${documentTypeLabel} 협의 코멘트 제출 - ${templateName || '기본계약서'}`,
template: "agreement-comment-notification",
context: {
language: "ko",
@@ -545,6 +612,7 @@ async function sendCommentNotificationEmail(params: {
authorType: authorType === 'SHI' ? '삼성중공업' : '협력업체',
comment: comment.comment,
templateName: templateName || '기본계약서',
+ documentTypeLabel,
vendorName: vendor?.vendorName || '',
attachmentCount,
contractUrl: `${process.env.NEXT_PUBLIC_APP_URL}/evcp/basic-contract/${contract.id}`,
@@ -617,18 +685,20 @@ export async function completeNegotiation(
.limit(1);
templateName = template?.templateName || null;
}
+ const documentTypeLabel = getContractDocumentLabel(templateName);
// 이메일 알림 발송
try {
if (requester) {
await sendEmail({
to: requester.email || '',
- subject: `[eVCP] GTC 기본계약서 협의 완료 - ${templateName || '기본계약서'}`,
+ subject: `[eVCP] ${documentTypeLabel} 협의 완료 - ${templateName || '기본계약서'}`,
template: "negotiation-complete-notification",
context: {
language: "ko",
recipientName: requester.name || "담당자",
templateName: templateName || '기본계약서',
+ documentTypeLabel,
vendorName: vendor?.vendorName || '',
contractUrl: `${process.env.NEXT_PUBLIC_APP_URL}/evcp/basic-contract/${contract.id}`,
systemUrl: process.env.NEXT_PUBLIC_APP_URL || 'https://evcp.com',