summaryrefslogtreecommitdiff
path: root/lib/sedp
diff options
context:
space:
mode:
Diffstat (limited to 'lib/sedp')
-rw-r--r--lib/sedp/get-tags.ts458
-rw-r--r--lib/sedp/sedp-token.ts4
2 files changed, 329 insertions, 133 deletions
diff --git a/lib/sedp/get-tags.ts b/lib/sedp/get-tags.ts
index 7c5661c3..7021d7d2 100644
--- a/lib/sedp/get-tags.ts
+++ b/lib/sedp/get-tags.ts
@@ -1,16 +1,16 @@
-// lib/sedp/get-tag.ts
-import db from "@/db/db";
-import {
+import db from "@/db/db";
+import {
contractItems,
- tags,
- forms,
- items,
- tagTypeClassFormMappings,
+ tags,
+ forms,
+ items,
+ tagTypeClassFormMappings,
projects,
tagTypes,
- tagClasses
+ tagClasses,
+ contracts
} from "@/db/schema";
-import { eq, and, like } from "drizzle-orm";
+import { eq, and, like, inArray } from "drizzle-orm";
import { getSEDPToken } from "./sedp-token";
/**
@@ -21,10 +21,10 @@ import { getSEDPToken } from "./sedp-token";
* @param progressCallback 진행 상황을 보고하기 위한 콜백 함수
* @returns 처리 결과 정보 (처리된 태그 수, 오류 목록 등)
*/
-// 함수 반환 타입 업데이트
export async function importTagsFromSEDP(
packageId: number,
- progressCallback?: (progress: number) => void
+ progressCallback?: (progress: number) => void,
+ mode?: string
): Promise<{
processedCount: number;
excludedCount: number;
@@ -44,8 +44,17 @@ export async function importTagsFromSEDP(
throw new Error(`Contract item with ID ${packageId} not found`);
}
- // 진행 상황 보고
- if (progressCallback) progressCallback(5);
+ // Step 1-2: 계약 아이템에서 계약 정보를 가져와 프로젝트 ID 획득
+ const contract = await db.query.contracts.findFirst({
+ where: eq(contracts.id, contractItem.contractId)
+ });
+
+ if (!contract) {
+ throw new Error(`Contract with ID ${contractItem.contractId} not found`);
+ }
+
+ // 프로젝트 ID 획득
+ const projectId = contract.projectId;
// Step 1-2: Get the item using itemId from contractItem
const item = await db.query.items.findFirst({
@@ -61,153 +70,340 @@ export async function importTagsFromSEDP(
// 진행 상황 보고
if (progressCallback) progressCallback(10);
- // Step 2: Find the mapping entry with the item code in remark field
- // 더 유연한 검색 패턴 사용 (%itemCode%)
- const mapping = await db.query.tagTypeClassFormMappings.findFirst({
- where: like(tagTypeClassFormMappings.remark, `%${itemCode}%`)
+ // 기본 매핑 검색 - 모든 모드에서 사용
+ const baseMappings = await db.query.tagTypeClassFormMappings.findMany({
+ where: and(
+ like(tagTypeClassFormMappings.remark, `%${itemCode}%`),
+ eq(tagTypeClassFormMappings.projectId, projectId)
+ )
});
-
- if (!mapping) {
+
+ if (baseMappings.length === 0) {
throw new Error(`No mapping found for item code ${itemCode}`);
}
- // 진행 상황 보고
- if (progressCallback) progressCallback(15);
-
- // Step 3: Get the project code
- const project = await db.query.projects.findFirst({
- where: eq(projects.id, mapping.projectId)
- });
+ // Step 2: Find the mapping entries - 모드에 따라 다른 조건 적용
+ let mappings = [];
+
+ if (mode === 'IM') {
+ // IM 모드일 때는 먼저 SEDP에서 태그 데이터를 가져와 TAG_TYPE_ID 리스트 확보
+
+ // 프로젝트 코드 가져오기
+ const project = await db.query.projects.findFirst({
+ where: eq(projects.id, projectId)
+ });
+
+ if (!project) {
+ throw new Error(`Project with ID ${projectId} not found`);
+ }
+
+ // 각 매핑의 formCode에 대해 태그 데이터 조회
+ const tagTypeIds = new Set<string>();
+
+ for (const mapping of baseMappings) {
+ try {
+ // SEDP에서 태그 데이터 가져오기
+ const tagData = await fetchTagDataFromSEDP(project.code, mapping.formCode);
+
+ // 첫 번째 키를 테이블 이름으로 사용
+ const tableName = Object.keys(tagData)[0];
+ const tagEntries = tagData[tableName];
+
+ if (Array.isArray(tagEntries)) {
+ // 모든 태그에서 TAG_TYPE_ID 수집
+ for (const entry of tagEntries) {
+ if (entry.TAG_TYPE_ID && entry.TAG_TYPE_ID !== "") {
+ tagTypeIds.add(entry.TAG_TYPE_ID);
+ }
+ }
+ }
+ } catch (error) {
+ console.error(`Error fetching tag data for formCode ${mapping.formCode}:`, error);
+ }
+ }
+
+ if (tagTypeIds.size === 0) {
+ throw new Error('No valid TAG_TYPE_ID found in SEDP tag data');
+ }
+
+ // 수집된 TAG_TYPE_ID로 tagTypes에서 정보 조회
+ const tagTypeInfo = await db.query.tagTypes.findMany({
+ where: and(
+ inArray(tagTypes.code, Array.from(tagTypeIds)),
+ eq(tagTypes.projectId, projectId)
+ )
+ });
+
+ if (tagTypeInfo.length === 0) {
+ throw new Error('No matching tag types found for the collected TAG_TYPE_IDs');
+ }
+
+ // 태그 타입 설명 수집
+ const tagLabels = tagTypeInfo.map(tt => tt.description);
+
+ // IM 모드에 맞는 매핑 조회 - ep가 "IMEP"인 항목만
+ mappings = await db.query.tagTypeClassFormMappings.findMany({
+ where: and(
+ inArray(tagTypeClassFormMappings.tagTypeLabel, tagLabels),
+ eq(tagTypeClassFormMappings.projectId, projectId),
+ eq(tagTypeClassFormMappings.ep, "IMEP")
+ )
+ });
+
+ } else {
+ // ENG 모드 또는 기본 모드일 때 - 기본 매핑 사용
+ mappings = [...baseMappings];
+
+ // ENG 모드에서는 ep 필드가 "IMEP"가 아닌 매핑만 필터링
+ if (mode === 'ENG') {
+ mappings = mappings.filter(mapping => mapping.ep !== "IMEP");
+ }
+ }
- if (!project) {
- throw new Error(`Project with ID ${mapping.projectId} not found`);
+ // 매핑이 없는 경우 모드에 따라 다른 오류 메시지 사용
+ if (mappings.length === 0) {
+ if (mode === 'IM') {
+ throw new Error('No suitable mappings found for IM mode');
+ } else {
+ throw new Error(`No mapping found for item code ${itemCode}`);
+ }
}
+
+ // 진행 상황 보고
+ if (progressCallback) progressCallback(15);
- const projectCode = project.code;
- const formCode = mapping.formCode;
+ // 결과 누적을 위한 변수들 초기화
+ let totalProcessedCount = 0;
+ let totalExcludedCount = 0;
+ let totalEntriesCount = 0;
+ const allErrors: string[] = [];
- // 진행 상황 보고
- if (progressCallback) progressCallback(20);
+ // 각 매핑에 대해 처리
+ for (let mappingIndex = 0; mappingIndex < mappings.length; mappingIndex++) {
+ const mapping = mappings[mappingIndex];
- // Step 4: Find the form ID
- const form = await db.query.forms.findFirst({
- where: and(
- eq(forms.contractItemId, packageId),
- eq(forms.formCode, formCode)
- )
- });
+ // Step 3: Get the project code
+ const project = await db.query.projects.findFirst({
+ where: eq(projects.id, mapping.projectId)
+ });
- let formId = form?.id;
+ if (!project) {
+ allErrors.push(`Project with ID ${mapping.projectId} not found`);
+ continue; // 다음 매핑으로 진행
+ }
- // If form doesn't exist, create it
- if (!form) {
- const insertResult = await db.insert(forms).values({
- contractItemId: packageId,
- formCode: formCode,
- formName: mapping.formName
- }).returning({ id: forms.id });
+ const projectCode = project.code;
- if (insertResult.length === 0) {
- throw new Error('Failed to create form record');
+ // IM 모드에서는 baseMappings에서 같은 formCode를 가진 매핑을 찾음
+ let formCode = mapping.formCode;
+ if (mode === 'IM') {
+ // baseMapping에서 동일한 formCode를 가진 매핑 찾기
+ const originalMapping = baseMappings.find(
+ baseMapping => baseMapping.formCode === mapping.formCode
+ );
+
+ // 찾았으면 해당 formCode 사용, 못 찾았으면 현재 매핑의 formCode 유지
+ if (originalMapping) {
+ formCode = originalMapping.formCode;
+ }
}
-
- formId = insertResult[0].id;
- }
- // 진행 상황 보고
- if (progressCallback) progressCallback(30);
+ // 진행 상황 보고 - 매핑별 진행률 조정
+ if (progressCallback) {
+ const baseProgress = 15;
+ const mappingProgress = Math.floor(15 * (mappingIndex + 1) / mappings.length);
+ progressCallback(baseProgress + mappingProgress);
+ }
- // Step 5: Call the external API to get tag data
- const tagData = await fetchTagDataFromSEDP(projectCode, formCode);
+ // Step 4: Find the form ID
+ const form = await db.query.forms.findFirst({
+ where: and(
+ eq(forms.contractItemId, packageId),
+ eq(forms.formCode, formCode)
+ )
+ });
- // 진행 상황 보고
- if (progressCallback) progressCallback(50);
+ let formId;
+
+ // If form doesn't exist, create it
+ if (!form) {
+ // 폼이 없는 경우 새로 생성 - 모드에 따른 필드 설정
+ const insertValues: any = {
+ contractItemId: packageId,
+ formCode: formCode,
+ formName: mapping.formName
+ };
+
+ // 모드 정보가 있으면 해당 필드 설정
+ if (mode) {
+ if (mode === "ENG") {
+ insertValues.eng = true;
+ } else if (mode === "IM") {
+ insertValues.im = true;
+ }
+ }
- // Step 6: Process the data and insert into the tags table
- let processedCount = 0;
- let excludedCount = 0;
- const errors: string[] = [];
+ const insertResult = await db.insert(forms).values(insertValues).returning({ id: forms.id });
- // Get the first key from the response as the table name
- const tableName = Object.keys(tagData)[0];
- const tagEntries = tagData[tableName];
+ if (insertResult.length === 0) {
+ allErrors.push(`Failed to create form record for formCode ${formCode}`);
+ continue; // 다음 매핑으로 진행
+ }
- if (!Array.isArray(tagEntries) || tagEntries.length === 0) {
- throw new Error('No tag data found in the API response');
- }
+ formId = insertResult[0].id;
+ } else {
+ // 폼이 이미 존재하는 경우 - 필요시 모드 필드 업데이트
+ formId = form.id;
+
+ if (mode) {
+ let shouldUpdate = false;
+ const updateValues: any = {};
+
+ if (mode === "ENG" && form.eng !== true) {
+ updateValues.eng = true;
+ shouldUpdate = true;
+ } else if (mode === "IM" && form.im !== true) {
+ updateValues.im = true;
+ shouldUpdate = true;
+ }
- const totalEntries = tagEntries.length;
+ if (shouldUpdate) {
+ await db.update(forms)
+ .set({
+ ...updateValues,
+ updatedAt: new Date()
+ })
+ .where(eq(forms.id, formId));
- // Process each tag entry
- for (let i = 0; i < tagEntries.length; i++) {
- try {
- const entry = tagEntries[i];
-
- // TAG_TYPE_ID가 null이거나 빈 문자열인 경우 제외
- if (entry.TAG_TYPE_ID === null || entry.TAG_TYPE_ID === "") {
- excludedCount++;
-
- // 주기적으로 진행 상황 보고 (건너뛰어도 진행률은 업데이트)
- if (progressCallback && (i % 10 === 0 || i === tagEntries.length - 1)) {
- progressCallback(Math.floor(50 + (i / tagEntries.length) * 50));
+ console.log(`Updated form ${formId} with ${mode} mode enabled`);
}
-
- continue; // 이 항목은 건너뜀
}
+ }
+
+ // 진행 상황 보고 - 매핑별 진행률 조정
+ if (progressCallback) {
+ const baseProgress = 30;
+ const mappingProgress = Math.floor(20 * (mappingIndex + 1) / mappings.length);
+ progressCallback(baseProgress + mappingProgress);
+ }
+
+ try {
+ // Step 5: Call the external API to get tag data
+
- // Get tag type description
- const tagType = await db.query.tagTypes.findFirst({
- where: and(
- eq(tagTypes.code, entry.TAG_TYPE_ID),
- eq(tagTypes.projectId, mapping.projectId)
- )
- });
-
- // Get tag class label
- const tagClass = await db.query.tagClasses.findFirst({
- where: and(
- eq(tagClasses.code, entry.CLS_ID),
- eq(tagClasses.projectId, mapping.projectId)
- )
- });
-
- // Insert or update the tag
- await db.insert(tags).values({
- contractItemId: packageId,
- formId: formId,
- tagNo: entry.TAG_NO,
- tagType: tagType?.description || entry.TAG_TYPE_ID,
- class: tagClass?.label || entry.CLS_ID,
- description: entry.TAG_DESC
- }).onConflictDoUpdate({
- target: [tags.contractItemId, tags.tagNo],
- set: {
- formId: formId,
- tagType: tagType?.description || entry.TAG_TYPE_ID,
- class: tagClass?.label || entry.CLS_ID,
- description: entry.TAG_DESC,
- updatedAt: new Date()
- }
- });
+ const tagData = await fetchTagDataFromSEDP(projectCode, baseMappings[0].formCode);
+
+ // 진행 상황 보고
+ if (progressCallback) {
+ const baseProgress = 50;
+ const mappingProgress = Math.floor(10 * (mappingIndex + 1) / mappings.length);
+ progressCallback(baseProgress + mappingProgress);
+ }
- processedCount++;
+ // Step 6: Process the data and insert into the tags table
+ let processedCount = 0;
+ let excludedCount = 0;
- // 주기적으로 진행 상황 보고
- if (progressCallback && (i % 10 === 0 || i === tagEntries.length - 1)) {
- progressCallback(Math.floor(50 + (i / tagEntries.length) * 50));
+ // Get the first key from the response as the table name
+ const tableName = Object.keys(tagData)[0];
+ const tagEntries = tagData[tableName];
+
+ if (!Array.isArray(tagEntries) || tagEntries.length === 0) {
+ allErrors.push(`No tag data found in the API response for formCode ${baseFormCode}`);
+ continue; // 다음 매핑으로 진행
}
+
+ const entriesCount = tagEntries.length;
+ totalEntriesCount += entriesCount;
+
+ // Process each tag entry
+ for (let i = 0; i < tagEntries.length; i++) {
+ try {
+ const entry = tagEntries[i];
+
+ // TAG_TYPE_ID가 null이거나 빈 문자열인 경우 제외
+ if (entry.TAG_TYPE_ID === null || entry.TAG_TYPE_ID === "") {
+ excludedCount++;
+ totalExcludedCount++;
+
+ // 주기적으로 진행 상황 보고 (건너뛰어도 진행률은 업데이트)
+ if (progressCallback && (i % 10 === 0 || i === tagEntries.length - 1)) {
+ const baseProgress = 60;
+ const entryProgress = Math.floor(30 * ((mappingIndex * entriesCount + i) / (mappings.length * entriesCount)));
+ progressCallback(baseProgress + entryProgress);
+ }
+
+ continue; // 이 항목은 건너뜀
+ }
+
+ // Get tag type description
+ const tagType = await db.query.tagTypes.findFirst({
+ where: and(
+ eq(tagTypes.code, entry.TAG_TYPE_ID),
+ eq(tagTypes.projectId, mapping.projectId)
+ )
+ });
+
+ // Get tag class label
+ const tagClass = await db.query.tagClasses.findFirst({
+ where: and(
+ eq(tagClasses.code, entry.CLS_ID),
+ eq(tagClasses.projectId, mapping.projectId)
+ )
+ });
+
+ // Insert or update the tag
+ await db.insert(tags).values({
+ contractItemId: packageId,
+ formId: formId,
+ tagNo: entry.TAG_NO,
+ tagType: tagType?.description || entry.TAG_TYPE_ID,
+ class: tagClass?.label || entry.CLS_ID,
+ description: entry.TAG_DESC
+ }).onConflictDoUpdate({
+ target: [tags.contractItemId, tags.tagNo],
+ set: {
+ formId: formId,
+ tagType: tagType?.description || entry.TAG_TYPE_ID,
+ class: tagClass?.label || entry.CLS_ID,
+ description: entry.TAG_DESC,
+ updatedAt: new Date()
+ }
+ });
+
+ processedCount++;
+ totalProcessedCount++;
+
+ // 주기적으로 진행 상황 보고
+ if (progressCallback && (i % 10 === 0 || i === tagEntries.length - 1)) {
+ const baseProgress = 60;
+ const entryProgress = Math.floor(30 * ((mappingIndex * entriesCount + i) / (mappings.length * entriesCount)));
+ progressCallback(baseProgress + entryProgress);
+ }
+ } catch (error: any) {
+ console.error(`Error processing tag entry:`, error);
+ allErrors.push(error.message || 'Unknown error');
+ }
+ }
+
+
} catch (error: any) {
- console.error(`Error processing tag entry:`, error);
- errors.push(error.message || 'Unknown error');
+ console.error(`Error processing mapping for formCode ${formCode}:`, error);
+ allErrors.push(`Error with formCode ${formCode}: ${error.message || 'Unknown error'}`);
}
}
+ // 모든 매핑 처리 완료 - 진행률 100%
+ if (progressCallback) {
+ progressCallback(100);
+ }
+
// 최종 결과 반환
return {
- processedCount,
- excludedCount,
- totalEntries,
- errors: errors.length > 0 ? errors : undefined
+ processedCount: totalProcessedCount,
+ excludedCount: totalExcludedCount,
+ totalEntries: totalEntriesCount,
+ errors: allErrors.length > 0 ? allErrors : undefined
};
} catch (error: any) {
console.error("Tag import error:", error);
@@ -226,10 +422,10 @@ async function fetchTagDataFromSEDP(projectCode: string, formCode: string): Prom
try {
// Get the token
const apiKey = await getSEDPToken();
-
+
// Define the API base URL
const SEDP_API_BASE_URL = process.env.SEDP_API_BASE_URL || 'http://sedpwebapi.ship.samsung.co.kr/api';
-
+
// Make the API call
const response = await fetch(
`${SEDP_API_BASE_URL}/Data/GetPubData`,
@@ -248,12 +444,12 @@ async function fetchTagDataFromSEDP(projectCode: string, formCode: string): Prom
})
}
);
-
+
if (!response.ok) {
const errorText = await response.text();
throw new Error(`SEDP API request failed: ${response.status} ${response.statusText} - ${errorText}`);
}
-
+
const data = await response.json();
return data;
} catch (error: any) {
diff --git a/lib/sedp/sedp-token.ts b/lib/sedp/sedp-token.ts
index dc419c87..9335a74e 100644
--- a/lib/sedp/sedp-token.ts
+++ b/lib/sedp/sedp-token.ts
@@ -1,7 +1,7 @@
// 환경 변수
const SEDP_API_BASE_URL = process.env.SEDP_API_BASE_URL || 'http://sedpwebapi.ship.samsung.co.kr/api';
const SEDP_API_USER_ID = process.env.SEDP_API_USER_ID || 'EVCPUSER';
-const SEDP_API_PASSWORD = process.env.SEDP_API_PASSWORD || 'evcpuser@2025';
+const SEDP_API_PASSWORD = process.env.SEDP_API_PASSWORD || 'evcpusr@2025';
/**
* SEDP API에서 인증 토큰을 가져옵니다.
@@ -10,7 +10,7 @@ const SEDP_API_PASSWORD = process.env.SEDP_API_PASSWORD || 'evcpuser@2025';
export async function getSEDPToken(): Promise<string> {
try {
const response = await fetch(
- `${SEDP_API_BASE_URL}/Security/RequestToken`,
+ `${SEDP_API_BASE_URL}/Security/RequestTokenWithMembership`,
{
method: 'POST',
headers: {