diff --git a/backend-node/src/services/menuCopyService.ts b/backend-node/src/services/menuCopyService.ts index 747d5427..f67e09a3 100644 --- a/backend-node/src/services/menuCopyService.ts +++ b/backend-node/src/services/menuCopyService.ts @@ -1127,6 +1127,16 @@ export class MenuCopyService { logger.info("\nπŸ”„ [6.5단계] 메뉴 URL ν™”λ©΄ ID μž¬λ§€ν•‘"); await this.updateMenuUrls(menuIdMap, screenIdMap, client); + // === 6.7단계: screen_group_screens 볡제 === + logger.info("\n🏷️ [6.7단계] screen_group_screens 볡제"); + await this.copyScreenGroupScreens( + screenIds, + screenIdMap, + sourceCompanyCode, + targetCompanyCode, + client + ); + // === 7단계: ν…Œμ΄λΈ” νƒ€μž… μ„€μ • 볡사 === if (additionalCopyOptions?.copyTableTypeColumns) { logger.info("\nπŸ“¦ [7단계] ν…Œμ΄λΈ” νƒ€μž… μ„€μ • 볡사"); @@ -2108,6 +2118,26 @@ export class MenuCopyService { logger.info(`πŸ“‚ 메뉴 볡사 쀑: ${menus.length}개`); + // screen_group_id μž¬λ§€ν•‘ λ§΅ 생성 (source company β†’ target company) + const screenGroupIdMap = new Map(); + const sourceGroupIds = [...new Set(menus.map(m => m.screen_group_id).filter(Boolean))] as number[]; + if (sourceGroupIds.length > 0) { + const sourceGroups = await client.query<{ id: number; group_name: string }>( + `SELECT id, group_name FROM screen_groups WHERE id = ANY($1)`, + [sourceGroupIds] + ); + for (const sg of sourceGroups.rows) { + const targetGroup = await client.query<{ id: number }>( + `SELECT id FROM screen_groups WHERE group_name = $1 AND company_code = $2 LIMIT 1`, + [sg.group_name, targetCompanyCode] + ); + if (targetGroup.rows.length > 0) { + screenGroupIdMap.set(sg.id, targetGroup.rows[0].id); + } + } + logger.info(`🏷️ screen_group λ§€ν•‘: ${screenGroupIdMap.size}/${sourceGroupIds.length}개`); + } + // μœ„μƒ μ •λ ¬ (λΆ€λͺ¨ λ¨Όμ € μ‚½μž…) const sortedMenus = this.topologicalSortMenus(menus); @@ -2252,7 +2282,7 @@ export class MenuCopyService { menu.menu_code, sourceMenuObjid, menu.menu_icon, - menu.screen_group_id, + menu.screen_group_id ? (screenGroupIdMap.get(menu.screen_group_id) || menu.screen_group_id) : null, ] ); @@ -2500,6 +2530,82 @@ export class MenuCopyService { logger.info(`βœ… 메뉴 URL μ—…λ°μ΄νŠΈ: ${updatedUrlCount}개, screen_code μ—…λ°μ΄νŠΈ: ${updatedCodeCount}개`); } + /** + * screen_group_screens 볡제 (ν™”λ©΄-슀크린그룹 λ§€ν•‘) + */ + private async copyScreenGroupScreens( + screenIds: Set, + screenIdMap: Map, + sourceCompanyCode: string, + targetCompanyCode: string, + client: PoolClient + ): Promise { + if (screenIds.size === 0 || screenIdMap.size === 0) { + logger.info("πŸ“­ screen_group_screens 볡제 λŒ€μƒ μ—†μŒ"); + return; + } + + // κΈ°μ‘΄ COMPANY_10의 screen_group_screens μ‚­μ œ (κΉ¨μ§„ 이전 데이터 정리) + await client.query( + `DELETE FROM screen_group_screens WHERE company_code = $1`, + [targetCompanyCode] + ); + + // μ†ŒμŠ€ νšŒμ‚¬μ˜ screen_group_screens 쑰회 + const sourceScreenIds = Array.from(screenIds); + const sourceResult = await client.query<{ + group_id: number; + screen_id: number; + screen_role: string; + display_order: number; + is_default: string; + }>( + `SELECT group_id, screen_id, screen_role, display_order, is_default + FROM screen_group_screens + WHERE company_code = $1 AND screen_id = ANY($2)`, + [sourceCompanyCode, sourceScreenIds] + ); + + if (sourceResult.rows.length === 0) { + logger.info("πŸ“­ μ†ŒμŠ€μ— screen_group_screens μ—†μŒ"); + return; + } + + // screen_group ID λ§€ν•‘ (source group_name β†’ target group_id) + const sourceGroupIds = [...new Set(sourceResult.rows.map(r => r.group_id))]; + const sourceGroups = await client.query<{ id: number; group_name: string }>( + `SELECT id, group_name FROM screen_groups WHERE id = ANY($1)`, + [sourceGroupIds] + ); + const groupIdMap = new Map(); + for (const sg of sourceGroups.rows) { + const targetGroup = await client.query<{ id: number }>( + `SELECT id FROM screen_groups WHERE group_name = $1 AND company_code = $2 LIMIT 1`, + [sg.group_name, targetCompanyCode] + ); + if (targetGroup.rows.length > 0) { + groupIdMap.set(sg.id, targetGroup.rows[0].id); + } + } + + let insertedCount = 0; + for (const row of sourceResult.rows) { + const newGroupId = groupIdMap.get(row.group_id); + const newScreenId = screenIdMap.get(row.screen_id); + if (!newGroupId || !newScreenId) continue; + + await client.query( + `INSERT INTO screen_group_screens (group_id, screen_id, screen_role, display_order, is_default, company_code, writer) + VALUES ($1, $2, $3, $4, $5, $6, 'system') + ON CONFLICT DO NOTHING`, + [newGroupId, newScreenId, row.screen_role, row.display_order, row.is_default, targetCompanyCode] + ); + insertedCount++; + } + + logger.info(`βœ… screen_group_screens 볡제: ${insertedCount}개`); + } + /** * μ½”λ“œ μΉ΄ν…Œκ³ λ¦¬ + μ½”λ“œ 볡사 (μ΅œμ ν™”: 배치 쑰회/μ‚½μž…) */