diff --git a/backend-node/src/services/menuCopyService.ts b/backend-node/src/services/menuCopyService.ts index bc80569f..26c8b779 100644 --- a/backend-node/src/services/menuCopyService.ts +++ b/backend-node/src/services/menuCopyService.ts @@ -738,18 +738,44 @@ export class MenuCopyService { ]); logger.info(` ✅ 메뉴 권한 삭제 완료`); - // 5-4. 채번 규칙의 menu_objid 참조 해제 (삭제하지 않고 연결만 끊음) - // 채번 규칙은 회사의 핵심 업무 데이터이므로 보존해야 함 + // 5-4. 채번 규칙 처리 (체크 제약조건 고려) + // scope_type = 'menu'인 채번 규칙: 메뉴 전용이므로 삭제 (파트 포함) + // check_menu_scope_requires_menu_objid 제약: scope_type='menu'이면 menu_objid NOT NULL 필수 + const menuScopedRulesResult = await client.query( + `SELECT rule_id FROM numbering_rules + WHERE menu_objid = ANY($1) AND company_code = $2 AND scope_type = 'menu'`, + [existingMenuIds, targetCompanyCode] + ); + if (menuScopedRulesResult.rows.length > 0) { + const menuScopedRuleIds = menuScopedRulesResult.rows.map( + (r) => r.rule_id + ); + // 채번 규칙 파트 먼저 삭제 + await client.query( + `DELETE FROM numbering_rule_parts WHERE rule_id = ANY($1)`, + [menuScopedRuleIds] + ); + // 채번 규칙 삭제 + await client.query(`DELETE FROM numbering_rules WHERE rule_id = ANY($1)`, [ + menuScopedRuleIds, + ]); + logger.info( + ` ✅ 메뉴 전용 채번 규칙 삭제: ${menuScopedRuleIds.length}개` + ); + } + + // scope_type != 'menu'인 채번 규칙: menu_objid만 NULL로 설정 (규칙 보존) const updatedNumberingRules = await client.query( `UPDATE numbering_rules SET menu_objid = NULL - WHERE menu_objid = ANY($1) AND company_code = $2 + WHERE menu_objid = ANY($1) AND company_code = $2 + AND (scope_type IS NULL OR scope_type != 'menu') RETURNING rule_id`, [existingMenuIds, targetCompanyCode] ); if (updatedNumberingRules.rowCount && updatedNumberingRules.rowCount > 0) { logger.info( - ` ✅ 채번 규칙 메뉴 연결 해제: ${updatedNumberingRules.rowCount}개 (데이터 보존됨)` + ` ✅ 테이블 스코프 채번 규칙 연결 해제: ${updatedNumberingRules.rowCount}개 (데이터 보존됨)` ); }