diff options
Diffstat (limited to 'lib/sedp/sync-package.ts')
| -rw-r--r-- | lib/sedp/sync-package.ts | 282 |
1 files changed, 282 insertions, 0 deletions
diff --git a/lib/sedp/sync-package.ts b/lib/sedp/sync-package.ts new file mode 100644 index 00000000..c8f39ad8 --- /dev/null +++ b/lib/sedp/sync-package.ts @@ -0,0 +1,282 @@ +"use server" +// src/lib/cron/syncItemsFromCodeLists.ts +import db from "@/db/db"; +import { projects, items } from '@/db/schema'; +import { eq } from 'drizzle-orm'; +import { getSEDPToken } from "./sedp-token"; + +const SEDP_API_BASE_URL = process.env.SEDP_API_BASE_URL || 'http://sedpwebapi.ship.samsung.co.kr/api'; + +async function getCodeLists(projectCode: string): Promise<Map<string, CodeList>> { + try { + // 토큰(API 키) 가져오기 + const apiKey = await getSEDPToken(); + + const response = await fetch( + `${SEDP_API_BASE_URL}/CodeList/Get`, + { + method: 'POST', + headers: { + 'Content-Type': 'application/json', + 'accept': '*/*', + 'ApiKey': apiKey, + 'ProjectNo': projectCode + }, + body: JSON.stringify({ + ProjectNo: projectCode, + ContainDeleted: false + }) + } + ); + + if (!response.ok) { + throw new Error(`코드 리스트 요청 실패: ${response.status} ${response.statusText}`); + } + + // 안전하게 JSON 파싱 + try { + const data = await response.json(); + + // 데이터가 배열인지 확인 + const codeLists: CodeList[] = Array.isArray(data) ? data : [data]; + + // CL_ID로 효율적인 조회를 위한 맵 생성 + const codeListMap = new Map<string, CodeList>(); + for (const codeList of codeLists) { + if (!codeList.DELETED) { + codeListMap.set(codeList.CL_ID, codeList); + } + } + + console.log(`프로젝트 ${projectCode}에서 ${codeListMap.size}개의 코드 리스트를 가져왔습니다`); + return codeListMap; + + } catch (parseError) { + console.error(`프로젝트 ${projectCode}의 코드 리스트 응답 파싱 실패:`, parseError); + // 응답 내용 로깅 + try { + const text = await response.clone().text(); + console.log(`응답 내용: ${text.substring(0, 200)}${text.length > 200 ? '...' : ''}`); + } catch (textError) { + console.error('응답 내용 로깅 실패:', textError); + } + return new Map(); + } + } catch (error) { + console.error(`프로젝트 ${projectCode}의 코드 리스트 가져오기 실패:`, error); + return new Map(); + } + } + + +interface CodeValue { + VALUE: string; + DESCC: string; + ATTRIBUTES: Array<{ + ATT_ID: string; + VALUE: string; + }>; +} + +interface CodeList { + PROJ_NO: string; + CL_ID: string; + DESC: string; + REMARK: string | null; + PRNT_CD_ID: string | null; + REG_TYPE_ID: string | null; + VAL_ATT_ID: string | null; + VALUES: CodeValue[]; + LNK_ATT: any[]; + DELETED: boolean; + CRTER_NO: string; + CRTE_DTM: string; + CHGER_NO: string | null; + CHGE_DTM: string | null; + _id: string; +} + +export async function syncItemsFromCodeLists(): Promise<void> { + try { + console.log('아이템 동기화 시작...'); + + // 모든 프로젝트 가져오기 + const allProjects = await db.select().from(projects); + console.log(`총 ${allProjects.length}개의 프로젝트를 처리합니다.`); + + let totalItemsProcessed = 0; + let totalItemsInserted = 0; + let totalItemsUpdated = 0; + + for (const project of allProjects) { + try { + console.log(`프로젝트 ${project.code} (${project.name}) 처리 중...`); + + // 프로젝트의 코드리스트 가져오기 + const codeListMap = await getCodeLists(project.code); + + // PKG_NO 코드리스트 찾기 + const pkgNoCodeList = codeListMap.get('PKG_NO'); + + if (!pkgNoCodeList) { + console.log(`프로젝트 ${project.code}에서 PKG_NO 코드리스트를 찾을 수 없습니다.`); + continue; + } + + console.log(`프로젝트 ${project.code}에서 ${pkgNoCodeList.VALUES.length}개의 아이템을 처리합니다.`); + + // VALUES 배열 순회하며 items 테이블에 삽입/업데이트 + for (const codeValue of pkgNoCodeList.VALUES) { + try { + // ATTRIBUTES에서 필요한 값들 추출 + const packageCodeAttr = codeValue.ATTRIBUTES?.find(attr => attr.ATT_ID === 'SHI_PACK_NO'); + const smCodeAttr = codeValue.ATTRIBUTES?.find(attr => attr.ATT_ID === 'SM_code'); + + const itemData = { + ProjectNo: project.code, + itemCode: codeValue.VALUE, + itemName: codeValue.DESCC || '', + packageCode: packageCodeAttr?.VALUE || '', + smCode: smCodeAttr?.VALUE || null, + description: null, // 필요시 추가 매핑 + parentItemCode: null, // 필요시 추가 매핑 + itemLevel: null, // 필요시 추가 매핑 + deleteFlag: 'N', // 기본값 + unitOfMeasure: null, // 필요시 추가 매핑 + steelType: null, // 필요시 추가 매핑 + gradeMaterial: null, // 필요시 추가 매핑 + changeDate: null, // 필요시 추가 매핑 + baseUnitOfMeasure: null, // 필요시 추가 매핑 + updatedAt: new Date() + }; + + // 기존 아이템 확인 (itemCode로 조회) + const existingItem = await db.select() + .from(items) + .where(eq(items.itemCode, codeValue.VALUE)) + .limit(1); + + if (existingItem.length > 0) { + // 기존 아이템 업데이트 + await db.update(items) + .set(itemData) + .where(eq(items.itemCode, codeValue.VALUE)); + totalItemsUpdated++; + } else { + // 새 아이템 삽입 + await db.insert(items).values(itemData); + totalItemsInserted++; + } + + totalItemsProcessed++; + } catch (itemError) { + console.error(`아이템 ${codeValue.VALUE} 처리 중 오류:`, itemError); + } + } + + console.log(`프로젝트 ${project.code} 완료`); + } catch (projectError) { + console.error(`프로젝트 ${project.code} 처리 중 오류:`, projectError); + } + } + + console.log(`아이템 동기화 완료:`); + console.log(`- 총 처리된 아이템: ${totalItemsProcessed}개`); + console.log(`- 새로 삽입된 아이템: ${totalItemsInserted}개`); + console.log(`- 업데이트된 아이템: ${totalItemsUpdated}개`); + + } catch (error) { + console.error('아이템 동기화 중 전체 오류:', error); + throw error; + } +} + +// 특정 프로젝트만 동기화하는 함수 +export async function syncItemsForProject(projectCode: string): Promise<void> { + try { + console.log(`프로젝트 ${projectCode}의 아이템 동기화 시작...`); + + // 프로젝트 존재 확인 + const project = await db.select() + .from(projects) + .where(eq(projects.code, projectCode)) + .limit(1); + + if (project.length === 0) { + throw new Error(`프로젝트 ${projectCode}를 찾을 수 없습니다.`); + } + + // 프로젝트의 코드리스트 가져오기 + const codeListMap = await getCodeLists(projectCode); + + // PKG_NO 코드리스트 찾기 + const pkgNoCodeList = codeListMap.get('PKG_NO'); + + if (!pkgNoCodeList) { + console.log(`프로젝트 ${projectCode}에서 PKG_NO 코드리스트를 찾을 수 없습니다.`); + return; + } + + console.log(`${pkgNoCodeList.VALUES.length}개의 아이템을 처리합니다.`); + + let itemsProcessed = 0; + let itemsInserted = 0; + let itemsUpdated = 0; + + // VALUES 배열 순회하며 items 테이블에 삽입/업데이트 + for (const codeValue of pkgNoCodeList.VALUES) { + try { + // ATTRIBUTES에서 필요한 값들 추출 + const packageCodeAttr = codeValue.ATTRIBUTES?.find(attr => attr.ATT_ID === 'SHI_PACK_NO'); + const smCodeAttr = codeValue.ATTRIBUTES?.find(attr => attr.ATT_ID === 'SM_code'); + + const itemData = { + ProjectNo: projectCode, + itemCode: codeValue.VALUE, + itemName: codeValue.DESCC || '', + packageCode: packageCodeAttr?.VALUE || '', + smCode: smCodeAttr?.VALUE || null, + description: null, + parentItemCode: null, + itemLevel: null, + deleteFlag: 'N', + unitOfMeasure: null, + steelType: null, + gradeMaterial: null, + changeDate: null, + baseUnitOfMeasure: null, + updatedAt: new Date() + }; + + // 기존 아이템 확인 + const existingItem = await db.select() + .from(items) + .where(eq(items.itemCode, codeValue.VALUE)) + .limit(1); + + if (existingItem.length > 0) { + await db.update(items) + .set(itemData) + .where(eq(items.itemCode, codeValue.VALUE)); + itemsUpdated++; + } else { + await db.insert(items).values(itemData); + itemsInserted++; + } + + itemsProcessed++; + } catch (itemError) { + console.error(`아이템 ${codeValue.VALUE} 처리 중 오류:`, itemError); + } + } + + console.log(`프로젝트 ${projectCode} 아이템 동기화 완료:`); + console.log(`- 처리된 아이템: ${itemsProcessed}개`); + console.log(`- 새로 삽입된 아이템: ${itemsInserted}개`); + console.log(`- 업데이트된 아이템: ${itemsUpdated}개`); + + } catch (error) { + console.error(`프로젝트 ${projectCode} 아이템 동기화 중 오류:`, error); + throw error; + } +}
\ No newline at end of file |
