summaryrefslogtreecommitdiff
path: root/lib/basic-contract
diff options
context:
space:
mode:
authordujinkim <dujin.kim@dtsolution.co.kr>2025-11-24 10:47:34 +0000
committerdujinkim <dujin.kim@dtsolution.co.kr>2025-11-24 10:47:34 +0000
commit8238c0c0ed6fd182d33f3437a22da1d80cfa928f (patch)
tree32982329788c38e515866de2338584eede8a5924 /lib/basic-contract
parentd79f56ae5a9e5f72781f78fe0399018cfac44081 (diff)
(임수민) 법무검토 요청 데이터 조회 수정
Diffstat (limited to 'lib/basic-contract')
-rw-r--r--lib/basic-contract/service.ts349
-rw-r--r--lib/basic-contract/sslvw-service.ts76
-rw-r--r--lib/basic-contract/status-detail/basic-contract-detail-table-toolbar-actions.tsx77
-rw-r--r--lib/basic-contract/status-detail/basic-contracts-detail-columns.tsx44
-rw-r--r--lib/basic-contract/status-detail/basic-contracts-detail-table.tsx1
-rw-r--r--lib/basic-contract/viewer/basic-contract-sign-viewer.tsx4
6 files changed, 397 insertions, 154 deletions
diff --git a/lib/basic-contract/service.ts b/lib/basic-contract/service.ts
index 55ac149e..6ae3c237 100644
--- a/lib/basic-contract/service.ts
+++ b/lib/basic-contract/service.ts
@@ -4,7 +4,7 @@ import { revalidateTag, unstable_noStore } from "next/cache";
import db from "@/db/db";
import { getErrorMessage } from "@/lib/handle-error";
import { unstable_cache } from "@/lib/unstable-cache";
-import { asc, desc, ilike, inArray, and, gte, lte, not, or, sql, eq, isNull, ne, isNotNull, count,like } from "drizzle-orm";
+import { asc, desc, ilike, inArray, and, gte, lte, not, or, sql, eq, isNull, ne, isNotNull, count,like, SQL } from "drizzle-orm";
import { v4 as uuidv4 } from "uuid";
import {
basicContract,
@@ -70,6 +70,7 @@ import { deleteFile, saveBuffer, saveFile, saveDRMFile } from "@/lib/file-stroag
import { decryptWithServerAction } from "@/components/drm/drmUtils";
import { getServerSession } from "next-auth/next"
import { authOptions } from "@/app/api/auth/[...nextauth]/route"
+import { getSSLVWPurInqReqByRegNo } from "./sslvw-service";
// 템플릿 추가
@@ -858,6 +859,7 @@ export async function getBasicContractsByTemplateId(
) {
// return unstable_cache(
// async () => {
+ // 법무검토 요청 데이터 조회 하는 오라클 sql 문에서 id 연결한 상태값 가져와서
try {
console.log(input.sort)
@@ -906,22 +908,29 @@ export async function getBasicContractsByTemplateId(
)
: [asc(basicContractView.createdAt)];
- // 트랜잭션 내부에서 Repository 호출
- const { data, total } = await db.transaction(async (tx) => {
- const data = await selectBasicContractsById(tx, {
- where,
- orderBy,
- offset,
- limit: input.perPage,
- });
+ const queryOptions = {
+ where,
+ orderBy,
+ offset,
+ limit: input.perPage,
+ }
- const total = await countBasicContractsById(tx, where);
- return { data, total };
- });
+ const initialResult = await loadBasicContractsByTemplate(queryOptions);
+ let finalData = initialResult.data;
+ let finalPageCount = Math.ceil(initialResult.total / input.perPage);
- const pageCount = Math.ceil(total / input.perPage);
+ try {
+ const synced = await syncLegalReviewStatusesForContracts(finalData);
+ if (synced) {
+ const refreshedResult = await loadBasicContractsByTemplate(queryOptions);
+ finalData = refreshedResult.data;
+ finalPageCount = Math.ceil(refreshedResult.total / input.perPage);
+ }
+ } catch (syncError) {
+ console.error('[getBasicContractsByTemplateId] 법무 상태 동기화 실패:', syncError);
+ }
- return { data, pageCount };
+ return { data: finalData, pageCount: finalPageCount };
} catch (err) {
// 에러 발생 시 디폴트\
console.log(err)
@@ -936,6 +945,75 @@ export async function getBasicContractsByTemplateId(
// )();
}
+const extractStatusText = (value: unknown): string => {
+ if (typeof value === 'string') {
+ return value.trim()
+ }
+ return ''
+}
+
+async function syncLegalReviewStatusesForContracts(
+ contracts: Array<{
+ id: number
+ legalReviewRegNo: string | null
+ legalReviewProgressStatus?: string | null
+ }>
+): Promise<boolean> {
+ const targets = contracts.filter((contract) => contract.legalReviewRegNo)
+ if (targets.length === 0) {
+ return false
+ }
+
+ let hasUpdates = false
+
+ for (const contract of targets) {
+ const regNo = contract.legalReviewRegNo!
+ const { success, data } = await getSSLVWPurInqReqByRegNo(regNo)
+
+ if (!success || !data) {
+ continue
+ }
+
+ const latestStatus = extractStatusText(data.PRGS_STAT_DSC ?? data.prgs_stat_dsc)
+ if (!latestStatus) {
+ continue
+ }
+
+ if (latestStatus === extractStatusText(contract.legalReviewProgressStatus)) {
+ continue
+ }
+
+ await persistLegalReviewStatus({
+ contractId: contract.id,
+ regNo,
+ progressStatus: latestStatus,
+ })
+
+ hasUpdates = true
+ }
+
+ return hasUpdates
+}
+
+async function loadBasicContractsByTemplate(options: {
+ where: SQL<unknown> | undefined
+ orderBy: SQL<unknown>[]
+ offset: number
+ limit: number
+}) {
+ return db.transaction(async (tx) => {
+ const data = await selectBasicContractsById(tx, {
+ where: options.where,
+ orderBy: options.orderBy,
+ offset: options.offset,
+ limit: options.limit,
+ });
+
+ const total = await countBasicContractsById(tx, options.where);
+ return { data, total };
+ });
+}
+
export async function getAllTemplates(): Promise<BasicContractTemplate[]> {
try {
return await findAllTemplates();
@@ -2784,6 +2862,47 @@ export async function requestLegalReviewAction(
}
}
+const persistLegalReviewStatus = async ({
+ contractId,
+ regNo,
+ progressStatus,
+}: {
+ contractId: number
+ regNo: string
+ progressStatus: string
+}) => {
+ const now = new Date()
+
+ await db.transaction(async (tx) => {
+ await tx
+ .update(basicContract)
+ .set({
+ legalReviewRegNo: regNo,
+ legalReviewProgressStatus: progressStatus,
+ updatedAt: now,
+ })
+ .where(eq(basicContract.id, contractId))
+
+ const existingLegalWork = await tx
+ .select({ id: legalWorks.id })
+ .from(legalWorks)
+ .where(eq(legalWorks.basicContractId, contractId))
+ .limit(1)
+
+ if (existingLegalWork[0]) {
+ await tx
+ .update(legalWorks)
+ .set({
+ status: progressStatus,
+ updatedAt: now,
+ })
+ .where(eq(legalWorks.id, existingLegalWork[0].id))
+ }
+ })
+
+ revalidateTag("basic-contracts")
+}
+
/**
* SSLVW 데이터로부터 법무검토 상태 업데이트
* @param sslvwData 선택된 SSLVW 데이터 배열
@@ -2791,7 +2910,7 @@ export async function requestLegalReviewAction(
* @returns 성공 여부 및 메시지
*/
export async function updateLegalReviewStatusFromSSLVW(
- sslvwData: Array<{ VEND_CD?: string; PRGS_STAT_DSC?: string; [key: string]: any }>,
+ sslvwData: Array<{ REG_NO?: string; reg_no?: string; PRGS_STAT_DSC?: string; prgs_stat_dsc?: string; [key: string]: any }>,
selectedContractIds: number[]
): Promise<{ success: boolean; message: string; updatedCount: number; errors: string[] }> {
try {
@@ -2815,90 +2934,92 @@ export async function updateLegalReviewStatusFromSSLVW(
}
}
- // 선택된 계약서 정보 조회
- const selectedContracts = await db
- .select({
- id: basicContractView.id,
- vendorCode: basicContractView.vendorCode,
- legalReviewStatus: basicContractView.legalReviewStatus
- })
- .from(basicContractView)
- .where(inArray(basicContractView.id, selectedContractIds))
-
- let updatedCount = 0
- const errors: string[] = []
-
- // 각 SSLVW 데이터에 대해 처리
- for (const sslvwItem of sslvwData) {
- const vendorCode = sslvwItem.VEND_CD || sslvwItem.vendorCode
- const prgsStatDsc = sslvwItem.PRGS_STAT_DSC || sslvwItem.prgsStatDsc
+ if (selectedContractIds.length !== 1) {
+ return {
+ success: false,
+ message: '한 개의 계약서만 선택해 주세요.',
+ updatedCount: 0,
+ errors: []
+ }
+ }
- if (!vendorCode || !prgsStatDsc) {
- errors.push(`벤더코드 또는 상태 정보가 없습니다: ${JSON.stringify(sslvwItem)}`)
- continue
+ if (sslvwData.length !== 1) {
+ return {
+ success: false,
+ message: '법무 시스템 데이터도 한 건만 선택해 주세요.',
+ updatedCount: 0,
+ errors: []
}
+ }
- // 해당 벤더의 선택된 계약서들 찾기
- const contractsToUpdate = selectedContracts.filter(contract =>
- contract.vendorCode === vendorCode
- )
+ const contractId = selectedContractIds[0]
+ const sslvwItem = sslvwData[0]
+ const regNo = String(
+ sslvwItem.REG_NO ??
+ sslvwItem.reg_no ??
+ sslvwItem.RegNo ??
+ ''
+ ).trim()
+ const progressStatus = String(
+ sslvwItem.PRGS_STAT_DSC ??
+ sslvwItem.prgs_stat_dsc ??
+ sslvwItem.PrgsStatDsc ??
+ ''
+ ).trim()
- if (contractsToUpdate.length === 0) {
- console.log(`벤더 ${vendorCode}의 선택된 계약서가 없음`)
- continue
+ if (!regNo) {
+ return {
+ success: false,
+ message: 'REG_NO 값을 찾을 수 없습니다.',
+ updatedCount: 0,
+ errors: []
}
+ }
- // PRGS_STAT_DSC를 legalWorks.status로 매핑
- const statusMapping: Record<string, string> = {
- '신규등록': '신규등록',
- '검토요청': '검토요청',
- '담당자배정': '담당자배정',
- '검토중': '검토중',
- '답변완료': '답변완료',
- '재검토요청': '재검토요청',
- '보류': '보류',
- '취소': '취소'
+ if (!progressStatus) {
+ return {
+ success: false,
+ message: 'PRGS_STAT_DSC 값을 찾을 수 없습니다.',
+ updatedCount: 0,
+ errors: []
}
+ }
- const mappedStatus = statusMapping[prgsStatDsc] || prgsStatDsc
+ const contract = await db
+ .select({
+ id: basicContract.id,
+ legalReviewRegNo: basicContract.legalReviewRegNo,
+ })
+ .from(basicContract)
+ .where(eq(basicContract.id, contractId))
+ .limit(1)
- // 각 계약서의 legalWorks 상태 업데이트
- for (const contract of contractsToUpdate) {
- try {
- const updateResult = await db
- .update(legalWorks)
- .set({
- status: mappedStatus,
- updatedAt: new Date()
- })
- .where(eq(legalWorks.basicContractId, contract.id))
- .returning({ id: legalWorks.id })
-
- if (updateResult.length > 0) {
- console.log(`법무작업 상태 업데이트: 계약서 ${contract.id}, 상태 ${mappedStatus}`)
- updatedCount++
- } else {
- console.log(`법무작업 레코드 없음: 계약서 ${contract.id}`)
- errors.push(`계약서 ${contract.id}: 법무작업 레코드가 없습니다`)
- }
- } catch (contractError) {
- console.error(`계약서 ${contract.id} 상태 업데이트 실패:`, contractError)
- errors.push(`계약서 ${contract.id}: 업데이트 실패`)
- }
+ if (!contract[0]) {
+ return {
+ success: false,
+ message: `계약서(${contractId})를 찾을 수 없습니다.`,
+ updatedCount: 0,
+ errors: []
}
}
- const message = updatedCount > 0
- ? `${updatedCount}건의 계약서 법무검토 상태가 업데이트되었습니다.`
- : '업데이트된 계약서가 없습니다.'
+ if (contract[0].legalReviewRegNo && contract[0].legalReviewRegNo !== regNo) {
+ console.warn(`[updateLegalReviewStatusFromSSLVW] REG_NO가 변경됩니다: ${contract[0].legalReviewRegNo} -> ${regNo}`)
+ }
+
+ await persistLegalReviewStatus({
+ contractId,
+ regNo,
+ progressStatus,
+ })
- console.log(`[updateLegalReviewStatusFromSSLVW] 완료: ${message}`)
+ console.log(`[updateLegalReviewStatusFromSSLVW] 완료: 계약서 ${contractId}, REG_NO ${regNo}, 상태 ${progressStatus}`)
return {
- success: updatedCount > 0,
- message,
- updatedCount,
- errors
+ success: true,
+ message: '법무검토 상태가 업데이트되었습니다.',
+ updatedCount: 1,
+ errors: []
}
} catch (error) {
@@ -2912,6 +3033,66 @@ export async function updateLegalReviewStatusFromSSLVW(
}
}
+export async function refreshLegalReviewStatusFromOracle(contractId: number): Promise<{
+ success: boolean
+ message: string
+ updated?: boolean
+}> {
+ try {
+ const contract = await db
+ .select({
+ id: basicContract.id,
+ legalReviewRegNo: basicContract.legalReviewRegNo,
+ legalReviewProgressStatus: basicContract.legalReviewProgressStatus,
+ })
+ .from(basicContract)
+ .where(eq(basicContract.id, contractId))
+ .limit(1)
+
+ if (!contract[0]) {
+ return { success: false, message: '계약서를 찾을 수 없습니다.' }
+ }
+
+ if (!contract[0].legalReviewRegNo) {
+ return { success: false, message: '연결된 REG_NO가 없습니다.' }
+ }
+
+ const { success, data, error } = await getSSLVWPurInqReqByRegNo(contract[0].legalReviewRegNo)
+
+ if (!success || !data) {
+ return { success: false, message: error ?? '법무 시스템 데이터를 찾을 수 없습니다.' }
+ }
+
+ const latestStatus = String(
+ data.PRGS_STAT_DSC ??
+ data.prgs_stat_dsc ??
+ ''
+ ).trim()
+
+ if (!latestStatus) {
+ return { success: false, message: '법무 시스템 상태 정보를 찾을 수 없습니다.' }
+ }
+
+ if (contract[0].legalReviewProgressStatus === latestStatus) {
+ return { success: true, message: '변경된 상태가 없습니다.', updated: false }
+ }
+
+ await persistLegalReviewStatus({
+ contractId,
+ regNo: contract[0].legalReviewRegNo,
+ progressStatus: latestStatus,
+ })
+
+ return { success: true, message: '법무검토 상태가 최신 정보로 업데이트되었습니다.', updated: true }
+ } catch (error) {
+ console.error('[refreshLegalReviewStatusFromOracle] 오류:', error)
+ return {
+ success: false,
+ message: error instanceof Error ? error.message : '법무검토 상태 새로고침 중 오류가 발생했습니다.'
+ }
+ }
+}
+
export async function resendContractsAction(contractIds: number[]) {
try {
// 세션 확인
diff --git a/lib/basic-contract/sslvw-service.ts b/lib/basic-contract/sslvw-service.ts
index 9650d43a..38ecb67d 100644
--- a/lib/basic-contract/sslvw-service.ts
+++ b/lib/basic-contract/sslvw-service.ts
@@ -25,6 +25,22 @@ const FALLBACK_TEST_DATA: SSLVWPurInqReq[] = [
}
]
+const normalizeOracleRows = (rows: Array<Record<string, unknown>>): SSLVWPurInqReq[] => {
+ return rows.map((item) => {
+ const convertedItem: SSLVWPurInqReq = {}
+ for (const [key, value] of Object.entries(item)) {
+ if (value instanceof Date) {
+ convertedItem[key] = value
+ } else if (value === null) {
+ convertedItem[key] = null
+ } else {
+ convertedItem[key] = String(value)
+ }
+ }
+ return convertedItem
+ })
+}
+
/**
* SSLVW_PUR_INQ_REQ 테이블 전체 조회
* @returns 테이블 데이터 배열
@@ -51,19 +67,7 @@ export async function getSSLVWPurInqReqData(): Promise<{
console.log(`✅ [getSSLVWPurInqReqData] 조회 성공 - ${rows.length}건`)
// 데이터 타입 변환 (필요에 따라 조정)
- const cleanedResult = rows.map((item) => {
- const convertedItem: SSLVWPurInqReq = {}
- for (const [key, value] of Object.entries(item)) {
- if (value instanceof Date) {
- convertedItem[key] = value
- } else if (value === null) {
- convertedItem[key] = null
- } else {
- convertedItem[key] = String(value)
- }
- }
- return convertedItem
- })
+ const cleanedResult = normalizeOracleRows(rows)
return {
success: true,
@@ -80,3 +84,49 @@ export async function getSSLVWPurInqReqData(): Promise<{
}
}
}
+
+export async function getSSLVWPurInqReqByRegNo(regNo: string): Promise<{
+ success: boolean
+ data?: SSLVWPurInqReq
+ error?: string
+}> {
+ if (!regNo) {
+ return {
+ success: false,
+ error: 'REG_NO는 필수입니다.'
+ }
+ }
+
+ try {
+ console.log(`[getSSLVWPurInqReqByRegNo] REG_NO=${regNo} 조회`)
+ const result = await oracleKnex.raw(
+ `
+ SELECT *
+ FROM SSLVW_PUR_INQ_REQ
+ WHERE REG_NO = :regNo
+ `,
+ { regNo }
+ )
+
+ const rows = (result.rows || result) as Array<Record<string, unknown>>
+ const cleanedResult = normalizeOracleRows(rows)
+
+ if (cleanedResult.length === 0) {
+ return {
+ success: false,
+ error: '해당 REG_NO에 대한 데이터가 없습니다.'
+ }
+ }
+
+ return {
+ success: true,
+ data: cleanedResult[0]
+ }
+ } catch (error) {
+ console.error('[getSSLVWPurInqReqByRegNo] 오류:', error)
+ return {
+ success: false,
+ error: error instanceof Error ? error.message : 'REG_NO 조회 중 오류가 발생했습니다.'
+ }
+ }
+}
diff --git a/lib/basic-contract/status-detail/basic-contract-detail-table-toolbar-actions.tsx b/lib/basic-contract/status-detail/basic-contract-detail-table-toolbar-actions.tsx
index e62a6cb7..b2cc5055 100644
--- a/lib/basic-contract/status-detail/basic-contract-detail-table-toolbar-actions.tsx
+++ b/lib/basic-contract/status-detail/basic-contract-detail-table-toolbar-actions.tsx
@@ -22,11 +22,19 @@ import { prepareFinalApprovalAction, quickFinalApprovalAction, resendContractsAc
import { BasicContractSignDialog } from "../vendor-table/basic-contract-sign-dialog"
import { SSLVWPurInqReqDialog } from "@/components/common/legal/sslvw-pur-inq-req-dialog"
import { requestRedFlagResolution } from "@/lib/compliance/red-flag-resolution"
+import { useRouter } from "next/navigation"
+
+interface RedFlagResolutionState {
+ resolved: boolean
+ resolvedAt: Date | null
+ pendingApprovalId: string | null
+}
interface BasicContractDetailTableToolbarActionsProps {
table: Table<BasicContractView>
gtcData?: Record<number, { gtcDocumentId: number | null; hasComments: boolean }>
redFlagData?: Record<number, boolean>
+ redFlagResolutionData?: Record<number, RedFlagResolutionState>
isComplianceTemplate?: boolean
}
@@ -34,6 +42,7 @@ export function BasicContractDetailTableToolbarActions({
table,
gtcData = {},
redFlagData = {},
+ redFlagResolutionData = {},
isComplianceTemplate = false
}: BasicContractDetailTableToolbarActionsProps) {
// 선택된 행들 가져오기
@@ -47,6 +56,7 @@ export function BasicContractDetailTableToolbarActions({
const [loading, setLoading] = React.useState(false)
const [buyerSignDialog, setBuyerSignDialog] = React.useState(false)
const [contractsToSign, setContractsToSign] = React.useState<any[]>([])
+ const router = useRouter()
// 각 버튼별 활성화 조건 계산
const canBulkDownload = hasSelectedRows && selectedRows.some(row =>
@@ -339,6 +349,11 @@ export function BasicContractDetailTableToolbarActions({
return
}
+ if (selectedRows.length !== 1) {
+ toast.error("계약서 한 건을 선택해주세요.")
+ return
+ }
+
try {
setLoading(true)
@@ -350,7 +365,7 @@ export function BasicContractDetailTableToolbarActions({
if (result.success) {
toast.success(result.message)
- // 테이블 데이터 갱신
+ router.refresh()
table.toggleAllPageRowsSelected(false)
} else {
toast.error(result.message)
@@ -391,27 +406,48 @@ export function BasicContractDetailTableToolbarActions({
}
}
- // RED FLAG 해소요청 가능 여부
- const canRequestRedFlagResolution = hasSelectedRows && isComplianceTemplate && selectedRows.some(row => {
- const contract = row.original
- return redFlagData[contract.id] === true
- })
+ const hasPendingResolution = (contractId: number) => {
+ const state = redFlagResolutionData[contractId]
+ return Boolean(state?.pendingApprovalId && !state?.resolved)
+ }
- // RED FLAG 해소요청 가능한 계약서들
- const redFlagResolutionContracts = selectedRows
+ const redFlagEligibleContracts = selectedRows
.map(row => row.original)
- .filter(contract => redFlagData[contract.id] === true)
+ .filter(contract => {
+ if (redFlagData[contract.id] !== true) return false
+ return !hasPendingResolution(contract.id)
+ })
+
+ const redFlagPendingContracts = selectedRows
+ .map(row => row.original)
+ .filter(contract => hasPendingResolution(contract.id))
+
+ const canRequestRedFlagResolution =
+ hasSelectedRows && isComplianceTemplate && redFlagEligibleContracts.length > 0
// RED FLAG 해소요청
const handleRequestRedFlagResolution = async () => {
if (!canRequestRedFlagResolution) {
- toast.error("RED FLAG가 있는 계약서를 선택해주세요")
+ toast.error("해소요청 가능한 RED FLAG 계약서를 선택해주세요")
return
}
+ if (redFlagPendingContracts.length > 0) {
+ const preview = redFlagPendingContracts
+ .map((contract) => contract.vendorName || `계약 ${contract.id}`)
+ .slice(0, 2)
+ .join(", ")
+ toast.info(
+ `${preview}${redFlagPendingContracts.length > 2 ? ` 외 ${redFlagPendingContracts.length - 2}건` : ""}은 해소요청이 이미 진행 중입니다.`,
+ {
+ description: "진행 중인 계약서는 자동으로 제외하고 요청합니다.",
+ }
+ )
+ }
+
setLoading(true)
try {
- const contractIds = redFlagResolutionContracts.map(c => c.id)
+ const contractIds = redFlagEligibleContracts.map(c => c.id)
const result = await requestRedFlagResolution(contractIds)
toast.success("RED FLAG 해소요청 결재가 상신되었습니다.", {
@@ -503,13 +539,15 @@ export function BasicContractDetailTableToolbarActions({
title={!hasSelectedRows
? "계약서를 선택해주세요"
: !canRequestRedFlagResolution
- ? "RED FLAG가 있는 계약서를 선택해주세요"
- : `${redFlagResolutionContracts.length}건 RED FLAG 해소요청`
+ ? redFlagPendingContracts.length > 0
+ ? "이미 해소요청이 진행 중인 계약서만 선택되어 있습니다"
+ : "RED FLAG가 있는 계약서를 선택해주세요"
+ : `${redFlagEligibleContracts.length}건 RED FLAG 해소요청`
}
>
<Flag className="size-4" aria-hidden="true" />
<span className="hidden sm:inline">
- RED FLAG 해소요청 {hasSelectedRows ? `(${redFlagResolutionContracts.length})` : ''}
+ RED FLAG 해소요청 {hasSelectedRows ? `(${redFlagEligibleContracts.length})` : ''}
</span>
</Button>
)}
@@ -530,7 +568,16 @@ export function BasicContractDetailTableToolbarActions({
</Button>
{/* 법무검토 버튼 (SSLVW 데이터 조회) */}
- <SSLVWPurInqReqDialog onConfirm={handleSSLVWConfirm} />
+ <SSLVWPurInqReqDialog
+ onConfirm={handleSSLVWConfirm}
+ requireSingleSelection
+ triggerDisabled={selectedRows.length !== 1 || loading}
+ triggerTitle={
+ selectedRows.length !== 1
+ ? "계약서 한 건을 선택해주세요"
+ : undefined
+ }
+ />
{/* 법무검토 요청 버튼 */}
<Button
diff --git a/lib/basic-contract/status-detail/basic-contracts-detail-columns.tsx b/lib/basic-contract/status-detail/basic-contracts-detail-columns.tsx
index 2ab39880..d03d0720 100644
--- a/lib/basic-contract/status-detail/basic-contracts-detail-columns.tsx
+++ b/lib/basic-contract/status-detail/basic-contracts-detail-columns.tsx
@@ -531,50 +531,14 @@ export function getDetailColumns({
),
cell: ({ row }) => {
const status = row.getValue("legalReviewStatus") as string | null
- const contract = row.original
- const requestedDate = contract.legalReviewRequestedAt as Date | null
- const completedDate = contract.legalReviewCompletedAt as Date | null
- // 법무검토 상태 우선, 없으면 기존 로직으로 판단
+ // PRGS_STAT_DSC 연동값 우선 표시
if (status) {
- const statusColors: Record<string, string> = {
- '신규등록': 'text-blue-600',
- '검토요청': 'text-purple-600',
- '담당자배정': 'text-orange-600',
- '검토중': 'text-yellow-600',
- '답변완료': 'text-green-600',
- '재검토요청': 'text-red-600',
- '보류': 'text-gray-500',
- '취소': 'text-red-700'
- }
-
- return (
- <div className={`text-sm ${statusColors[status] || 'text-gray-600'}`}>
- <div className="font-medium">{status}</div>
- </div>
- )
+ return <div className="text-sm text-gray-800">{status}</div>
}
- // legalWorks에 데이터가 없는 경우 기존 로직 사용
- if (completedDate) {
- return (
- <div className="text-sm text-green-600">
- <div className="font-medium">완료</div>
- <div className="text-xs">{formatDateTime(completedDate, "KR")}</div>
- </div>
- )
- } else if (requestedDate) {
- return (
- <div className="text-sm text-orange-600">
- <div className="font-medium">진행중</div>
- <div className="text-xs">검토 대기</div>
- </div>
- )
- } else {
- return (
- <div className="text-sm text-gray-400">-</div>
- )
- }
+ // 동기화된 값이 없으면 빈 값 처리
+ return <div className="text-sm text-gray-400">-</div>
},
minSize: 140,
},
diff --git a/lib/basic-contract/status-detail/basic-contracts-detail-table.tsx b/lib/basic-contract/status-detail/basic-contracts-detail-table.tsx
index 010b4713..a2e1c5e4 100644
--- a/lib/basic-contract/status-detail/basic-contracts-detail-table.tsx
+++ b/lib/basic-contract/status-detail/basic-contracts-detail-table.tsx
@@ -266,6 +266,7 @@ type RedFlagResolutionState = {
table={table}
gtcData={gtcData}
redFlagData={redFlagData}
+ redFlagResolutionData={redFlagResolutionData}
isComplianceTemplate={isComplianceTemplate}
/>
</DataTableAdvancedToolbar>
diff --git a/lib/basic-contract/viewer/basic-contract-sign-viewer.tsx b/lib/basic-contract/viewer/basic-contract-sign-viewer.tsx
index 6bf0dfb1..8185e33e 100644
--- a/lib/basic-contract/viewer/basic-contract-sign-viewer.tsx
+++ b/lib/basic-contract/viewer/basic-contract-sign-viewer.tsx
@@ -1411,7 +1411,7 @@ export function BasicContractSignViewer({
{file.name}
</span>
{isSurveyTab && !surveyData.completed && (
- <Badge variant="destructive" className="ml-1 h-4 px-1.5 text-xs bg-amber-500 text-white">
+ <Badge variant="destructive" className="ml-1 h-4 px-1.5 text-xs bg-red-500 text-white transition-none hover:bg-red-500">
필수
</Badge>
)}
@@ -1640,7 +1640,7 @@ export function BasicContractSignViewer({
{file.name}
</span>
{isSurveyTab && !surveyData.completed && (
- <Badge variant="destructive" className="ml-1 h-4 px-1.5 text-xs bg-amber-500 text-white">
+ <Badge variant="destructive" className="ml-1 h-4 px-1.5 text-xs bg-red-500 text-white transition-none hover:bg-red-500">
필수
</Badge>
)}