summaryrefslogtreecommitdiff
path: root/lib/forms-plant
diff options
context:
space:
mode:
Diffstat (limited to 'lib/forms-plant')
-rw-r--r--lib/forms-plant/services.ts186
1 files changed, 173 insertions, 13 deletions
diff --git a/lib/forms-plant/services.ts b/lib/forms-plant/services.ts
index 99e7c35b..fae38446 100644
--- a/lib/forms-plant/services.ts
+++ b/lib/forms-plant/services.ts
@@ -1469,7 +1469,7 @@ async function transformDataToSEDPFormat(
SCOPE: packageCode,
TOOLID: "eVCP", // Changed from VDCS
ITM_NO: row.TAG_NO || "",
- OP_DELETE: false,
+ OP_DELETE: row.status === "Deleted", // Set OP_DELETE based on status
MAIN_YN: true,
LAST_REV_YN: true,
CRTER_NO: designerNo,
@@ -1627,7 +1627,22 @@ export async function sendDataToSEDP(
// Define the API base URL
const SEDP_API_BASE_URL = process.env.SEDP_API_BASE_URL || 'http://sedpwebapi.ship.samsung.co.kr/api';
- console.log("Sending data to SEDP:", JSON.stringify(sedpData, null, 2));
+ console.log("=".repeat(80));
+ console.log("[SEDP Overwrite API] 요청 시작");
+ console.log(`[SEDP Overwrite API] URL: ${SEDP_API_BASE_URL}/AdapterData/Overwrite`);
+ console.log(`[SEDP Overwrite API] ProjectNo: ${projectCode}`);
+ console.log("[SEDP Overwrite API] Request Body (전체):");
+ console.log(JSON.stringify(sedpData, null, 2));
+
+ // Check if there are any items with OP_DELETE=true
+ const deleteItems = sedpData.filter(item => item.OP_DELETE === true);
+ if (deleteItems.length > 0) {
+ console.log("=".repeat(80));
+ console.log(`[SEDP DELETE] ⚠️ OP_DELETE=true인 항목 ${deleteItems.length}개 발견`);
+ console.log("[SEDP DELETE] 삭제 요청 항목만 추출:");
+ console.log(JSON.stringify(deleteItems, null, 2));
+ }
+ console.log("=".repeat(80));
// Make the API call
const response = await fetch(
@@ -1747,6 +1762,11 @@ export async function sendFormDataToSEDP(
// Update status for sent tags
const updatedDataArray = dataArray.map(item => {
if (item.TAG_NO && sentTagNumbers.has(item.TAG_NO)) {
+ // 삭제된 항목(status="Deleted")은 status를 유지하고,
+ // 나머지 항목만 "Sent to S-EDP"로 변경
+ if (item.status === "Deleted") {
+ return item; // Keep status="Deleted" unchanged
+ }
return {
...item,
status: "Sent to S-EDP" // SEDP로 전송된 데이터임을 표시
@@ -1793,15 +1813,19 @@ export async function deleteFormDataByTags({
formCode,
contractItemId,
tagIdxs,
+ projectId,
}: {
formCode: string
contractItemId: number
tagIdxs: string[]
+ projectId?: number
}): Promise<{
error?: string
success?: boolean
deletedCount?: number
deletedTagsCount?: number
+ sedpDeleteSuccess?: boolean
+ sedpDeleteError?: string
}> {
try {
// 입력 검증
@@ -1811,11 +1835,36 @@ export async function deleteFormDataByTags({
}
}
- console.log(`[DELETE ACTION] Deleting tags for formCode: ${formCode}, contractItemId: ${contractItemId}, tagNos:`, tagIdxs)
+ console.log(`[DELETE ACTION] Deleting tags for formCode: ${formCode}, contractItemId: ${contractItemId}, tagIdxs:`, tagIdxs)
- // 트랜잭션으로 안전하게 처리
+ // 1. 트랜잭션 전에 삭제할 항목들을 미리 조회하여 저장 (S-EDP 전송용)
+ const entryForSedp = await db
+ .select()
+ .from(formEntries)
+ .where(
+ and(
+ eq(formEntries.formCode, formCode),
+ eq(formEntries.contractItemId, contractItemId)
+ )
+ )
+ .orderBy(desc(formEntries.updatedAt))
+ .limit(1)
+
+ let itemsToSendToSedp: Record<string, unknown>[] = []
+
+ if (entryForSedp.length > 0) {
+ const dataForSedp = Array.isArray(entryForSedp[0].data) ? entryForSedp[0].data : []
+ // 삭제할 항목들만 추출 (S-EDP로 OP_DELETE=true 전송용)
+ itemsToSendToSedp = dataForSedp.filter((item: Record<string, unknown>) =>
+ tagIdxs.includes(item.TAG_IDX as string)
+ )
+
+ console.log(`[DELETE ACTION] Found ${itemsToSendToSedp.length} items to send to SEDP before deletion`)
+ }
+
+ // 2. 트랜잭션으로 안전하게 처리 (완전 삭제)
const result = await db.transaction(async (tx) => {
- // 1. 현재 formEntry 데이터 가져오기
+ // 2-1. 현재 formEntry 데이터 가져오기
const currentEntryResult = await tx
.select()
.from(formEntries)
@@ -1833,25 +1882,25 @@ export async function deleteFormDataByTags({
}
const currentEntry = currentEntryResult[0]
- let currentData = Array.isArray(currentEntry.data) ? currentEntry.data : []
+ const currentData = Array.isArray(currentEntry.data) ? currentEntry.data : []
console.log(`[DELETE ACTION] Current data count: ${currentData.length}`)
- // 2. 삭제할 항목들 필터링 (formEntries에서)
- const updatedData = currentData.filter((item: any) =>
- !tagIdxs.includes(item.TAG_IDX)
+ // 2-2. 삭제할 항목들을 완전히 제거 (status 마킹이 아님)
+ const updatedData = currentData.filter((item: Record<string, unknown>) =>
+ !tagIdxs.includes(item.TAG_IDX as string)
)
const deletedFromFormEntries = currentData.length - updatedData.length
console.log(`[DELETE ACTION] Updated data count: ${updatedData.length}`)
- console.log(`[DELETE ACTION] Deleted ${deletedFromFormEntries} items from formEntries`)
+ console.log(`[DELETE ACTION] Completely removed ${deletedFromFormEntries} items from formEntries`)
if (deletedFromFormEntries === 0) {
throw new Error("No items were found to delete in formEntries")
}
- // 3. tags 테이블에서 해당 태그들 삭제
+ // 2-3. tags 테이블에서 해당 태그들 삭제
const deletedTagsResult = await tx
.delete(tags)
.where(
@@ -1867,7 +1916,7 @@ export async function deleteFormDataByTags({
console.log(`[DELETE ACTION] Deleted ${deletedTagsCount} items from tags table`)
console.log(`[DELETE ACTION] Deleted tag numbers:`, deletedTagsResult.map(t => t.tagNo))
- // 4. formEntries 데이터 업데이트
+ // 2-4. formEntries 데이터 업데이트 (삭제된 항목 제외)
await tx
.update(formEntries)
.set({
@@ -1888,7 +1937,115 @@ export async function deleteFormDataByTags({
}
})
- // 5. 캐시 무효화
+ // 3. SEDP에 OP_DELETE=true로 전송 (projectId가 제공된 경우)
+ let sedpDeleteSuccess = false
+ let sedpDeleteError: string | undefined
+
+ if (projectId) {
+ try {
+ console.log(`[DELETE ACTION] Attempting to send deleted items to SEDP for projectId: ${projectId}`)
+
+ // 미리 저장해둔 삭제 항목들 사용
+ const deletedItems = itemsToSendToSedp
+
+ if (deletedItems.length > 0) {
+ console.log(`[DELETE ACTION] Found ${deletedItems.length} deleted items before deduplication`)
+
+ // 삭제 항목들에 status="Deleted" 마킹 (S-EDP에서 OP_DELETE=true로 전송하기 위해)
+ const deletedItemsWithStatus = deletedItems.map((item: Record<string, unknown>) => ({
+ ...item,
+ status: "Deleted"
+ } as Record<string, unknown>))
+
+ console.log(`[DELETE ACTION] Deleted items TAG_NO list:`, deletedItemsWithStatus.map(item => ({
+ TAG_NO: item.TAG_NO,
+ TAG_IDX: item.TAG_IDX
+ })))
+
+ // Deduplicate by TAG_NO: keep only the oldest TAG_IDX for each TAG_NO
+ // S-EDP has a unique key on (PROJ_NO, TOOLID, SCOPE, REV_NO, ITM_NO)
+ // ITM_NO is mapped to TAG_NO, so we need to ensure only ONE item per TAG_NO
+ const tagNoMap = new Map<string, Record<string, unknown>>();
+
+ for (const item of deletedItemsWithStatus) {
+ const tagNo = item.TAG_NO as string;
+ const tagIdx = item.TAG_IDX as string;
+
+ if (!tagNo) {
+ console.warn(`[DELETE ACTION] Skipping item without TAG_NO`);
+ continue;
+ }
+
+ if (!tagIdx) {
+ console.warn(`[DELETE ACTION] Skipping item without TAG_IDX for TAG_NO "${tagNo}"`);
+ continue;
+ }
+
+ if (!tagNoMap.has(tagNo)) {
+ console.log(`[DELETE ACTION] TAG_NO "${tagNo}": Adding first occurrence with TAG_IDX ${tagIdx}`);
+ tagNoMap.set(tagNo, item);
+ } else {
+ // Compare TAG_IDX (MongoDB ObjectID) - keep the oldest one
+ const existingItem = tagNoMap.get(tagNo)!;
+ const existingTagIdx = existingItem.TAG_IDX as string;
+
+ // MongoDB ObjectID는 시간순으로 정렬 가능 (사전순으로 작은 값이 더 오래됨)
+ if (tagIdx < existingTagIdx) {
+ console.log(`[DELETE ACTION] TAG_NO "${tagNo}": Replacing TAG_IDX ${existingTagIdx} with older ${tagIdx}`);
+ tagNoMap.set(tagNo, item);
+ } else {
+ console.log(`[DELETE ACTION] TAG_NO "${tagNo}": Skipping TAG_IDX ${tagIdx} (keeping older ${existingTagIdx})`);
+ }
+ }
+ }
+
+ const uniqueDeletedItems = Array.from(tagNoMap.values());
+ console.log(`[DELETE ACTION] ✓ Deduplication complete: ${deletedItemsWithStatus.length} items → ${uniqueDeletedItems.length} unique items`)
+ console.log(`[DELETE ACTION] Final items to send to SEDP:`, uniqueDeletedItems.map(item => ({
+ TAG_NO: item.TAG_NO,
+ TAG_IDX: item.TAG_IDX
+ })))
+
+ // Get form meta to get columns
+ const formMetaResult = await db.query.formMetas.findFirst({
+ where: and(
+ eq(formMetas.formCode, formCode),
+ eq(formMetas.projectId, projectId)
+ )
+ })
+
+ if (formMetaResult && formMetaResult.columns) {
+ // Send deleted items to SEDP (will have OP_DELETE=true)
+ const sedpResult = await sendFormDataToSEDP(
+ formCode,
+ projectId,
+ contractItemId,
+ uniqueDeletedItems as GenericData[],
+ formMetaResult.columns as DataTableColumnJSON[]
+ )
+
+ if (sedpResult.success) {
+ sedpDeleteSuccess = true
+ console.log(`[DELETE ACTION] Successfully sent ${uniqueDeletedItems.length} unique deleted items to SEDP with OP_DELETE=true`)
+ } else {
+ sedpDeleteError = sedpResult.message
+ console.error(`[DELETE ACTION] Failed to send deleted items to SEDP:`, sedpResult.message)
+ }
+ } else {
+ sedpDeleteError = "Form meta or columns not found"
+ console.warn(`[DELETE ACTION] Form meta not found for formCode: ${formCode}, projectId: ${projectId}`)
+ }
+ } else {
+ console.warn(`[DELETE ACTION] No deleted items found to send to SEDP`)
+ }
+ } catch (sedpError) {
+ sedpDeleteError = sedpError instanceof Error ? sedpError.message : "SEDP delete failed"
+ console.error(`[DELETE ACTION] SEDP delete error:`, sedpError)
+ // SEDP 삭제 실패는 경고로만 처리 (로컬 삭제는 성공했으므로)
+ }
+ }
+
+ // 4. 캐시 무효화
const cacheKey = `form-data-${formCode}-${contractItemId}`
revalidateTag(cacheKey)
revalidateTag(`tags-${contractItemId}`)
@@ -1898,11 +2055,14 @@ export async function deleteFormDataByTags({
console.log(`[DELETE ACTION] Transaction completed successfully`)
console.log(`[DELETE ACTION] FormEntries deleted: ${result.deletedFromFormEntries}`)
console.log(`[DELETE ACTION] Tags deleted: ${result.deletedTagsCount}`)
+ console.log(`[DELETE ACTION] SEDP delete success: ${sedpDeleteSuccess}`)
return {
success: true,
deletedCount: result.deletedFromFormEntries,
deletedTagsCount: result.deletedTagsCount,
+ sedpDeleteSuccess,
+ sedpDeleteError,
}
} catch (error) {