From 2348800e68ac0e7b0a748a519e5612d8f727fab6 Mon Sep 17 00:00:00 2001 From: DDD1542 Date: Fri, 15 May 2026 16:50:50 +0900 Subject: [PATCH] =?UTF-8?q?refactor(common-code):=20=EB=A7=88=EC=8A=A4?= =?UTF-8?q?=ED=84=B0-=EB=94=94=ED=85=8C=EC=9D=BC=20=EC=9E=AC=EC=84=A4?= =?UTF-8?q?=EA=B3=84=20=E2=80=94=20code=5Finfo(=EA=B7=B8=EB=A3=B9)=20+=20c?= =?UTF-8?q?ode=5Fdetail(=EC=9E=AC=EA=B7=80=20=ED=8A=B8=EB=A6=AC)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 카테고리/캐스케이딩 시스템 (B/C/D) 전부 폐기: - BE: mapper/Service/Controller 9세트 삭제 (cascading*, categoryTree, tableCategoryValue, categoryValueCascading, codeMerge) - FE: 페이지 3 + API 8 + hooks 2 + 폐기 컴포넌트 6 삭제, 14곳 의존성 정리 - DB: 12 테이블 DROP, TABLE_TYPE_COLUMNS.CODE_CATEGORY → CODE_INFO rename 신설 commonCode 마스터-디테일: - code_info: 1레벨 그룹 마스터 - code_detail: 2~∞ depth 재귀 트리 (parent_detail_id self-FK, depth 자동 계산) - API: /api/common-codes/{info,detail} - CodeCategoryFormModal/Panel → CodeInfoFormModal/Panel rename - code_category 컬럼명 전부 code_info 로 치환 (mapper/Java/FE) - 옛 commonCode API URL (/categories/...) → getCodeOptions 어댑터 + /detail?code_info=... 전환 Co-Authored-By: Claude Opus 4.7 (1M context) --- .../CascadingAutoFillController.java | 125 - .../CascadingConditionController.java | 81 - .../CascadingHierarchyController.java | 157 -- .../CascadingMutualExclusionController.java | 121 - .../CascadingRelationController.java | 139 - .../controller/CategoryTreeController.java | 191 -- .../CategoryValueCascadingController.java | 142 - .../erp/controller/CodeMergeController.java | 69 - .../erp/controller/CommonCodeController.java | 334 +-- .../controller/EntityReferenceController.java | 12 +- .../ScreenManagementController.java | 4 +- .../TableCategoryValueController.java | 373 --- .../erp/service/CascadingAutoFillService.java | 270 -- .../service/CascadingConditionService.java | 198 -- .../service/CascadingHierarchyService.java | 251 -- .../CascadingMutualExclusionService.java | 175 -- .../erp/service/CascadingRelationService.java | 193 -- .../com/erp/service/CategoryTreeService.java | 415 --- .../CategoryValueCascadingService.java | 270 -- .../com/erp/service/CodeMergeService.java | 247 -- .../com/erp/service/CommonCodeService.java | 571 ++-- .../erp/service/EntityReferenceService.java | 8 +- .../com/erp/service/EntitySearchService.java | 8 +- .../erp/service/ScreenManagementService.java | 8 +- .../service/TableCategoryValueService.java | 368 --- .../erp/service/TableManagementService.java | 2 +- .../resources/mapper/cascadingAutoFill.xml | 128 - .../resources/mapper/cascadingCondition.xml | 100 - .../resources/mapper/cascadingHierarchy.xml | 219 -- .../mapper/cascadingMutualExclusion.xml | 145 - .../resources/mapper/cascadingRelation.xml | 160 -- .../main/resources/mapper/categoryTree.xml | 182 -- .../mapper/categoryValueCascading.xml | 179 -- .../src/main/resources/mapper/codeMerge.xml | 30 - .../src/main/resources/mapper/commonCode.xml | 617 +++-- .../main/resources/mapper/entityReference.xml | 2 +- .../main/resources/mapper/entitySearch.xml | 8 +- .../src/main/resources/mapper/meta.xml | 2 +- .../resources/mapper/screenManagement.xml | 14 +- .../resources/mapper/tableCategoryValue.xml | 470 ---- .../main/resources/mapper/tableManagement.xml | 14 +- frontend/app/(main)/admin/audit-log/page.tsx | 2 +- frontend/app/(main)/admin/auto-fill/page.tsx | 21 - .../admin/cascading-management/page.tsx | 115 - .../cascading-management/tabs/AutoFillTab.tsx | 687 ----- .../tabs/CascadingRelationsTab.tsx | 899 ------- .../tabs/CategoryValueCascadingTab.tsx | 1009 ------- .../tabs/ConditionTab.tsx | 502 ---- .../tabs/HierarchyColumnTab.tsx | 627 ----- .../tabs/HierarchyTab.tsx | 847 ------ .../tabs/MutualExclusionTab.tsx | 582 ---- .../(main)/admin/cascading-relations/page.tsx | 21 - .../admin/systemMng/commonCodeList/page.tsx | 32 +- .../admin/systemMng/tableMngList/page.tsx | 41 +- .../admin/CodeCategoryFormModal.tsx | 389 --- frontend/components/admin/CodeDetailPanel.tsx | 461 ++-- frontend/components/admin/CodeFormModal.tsx | 408 +-- .../components/admin/CodeInfoFormModal.tsx | 357 +++ .../{CategoryItem.tsx => CodeInfoItem.tsx} | 54 +- ...odeCategoryPanel.tsx => CodeInfoPanel.tsx} | 119 +- frontend/components/admin/MenuCopyDialog.tsx | 14 +- .../components/admin/SortableCodeItem.tsx | 163 +- .../admin/table-type/ColumnDetailPanel.tsx | 12 +- .../admin/table-type/ColumnGrid.tsx | 2 +- frontend/components/admin/table-type/types.ts | 2 +- .../components/common/CascadingDropdown.tsx | 188 -- .../components/common/ExcelUploadModal.tsx | 358 +-- .../common/HierarchicalCodeSelect.tsx | 498 ++-- .../common/MultiColumnHierarchySelect.tsx | 370 +-- .../common/MultiTableExcelUploadModal.tsx | 348 +-- .../dataflow/condition/WebTypeInput.tsx | 26 +- .../ActionConfig/ActionConditionBuilder.tsx | 4 +- .../RightPanel/ControlConditionStep.tsx | 2 +- .../components/layout/AdminPageRenderer.tsx | 5 - .../numbering-rule/AutoConfigPanel.tsx | 627 +---- .../screen/InteractiveDataTable.tsx | 133 +- .../screen/InteractiveScreenViewer.tsx | 140 +- frontend/components/screen/InvyoneStudio.tsx | 26 +- .../components/screen/LayerConditionPanel.tsx | 28 +- .../components/screen/LayerManagerPanel.tsx | 8 +- .../components/screen/ScreenSettingModal.tsx | 2 +- .../components/screen/TableSettingModal.tsx | 14 +- .../config-panels/DataFilterConfigPanel.tsx | 130 +- .../config-panels/SelectConfigPanel.tsx | 211 +- .../screen/filters/AdvancedSearchFilters.tsx | 30 +- .../screen/panels/DataTableConfigPanel.tsx | 2 +- .../screen/widgets/CategoryWidget.tsx | 96 +- .../screen/widgets/types/CodeWidget.tsx | 14 +- .../AddCategoryColumnDialog.tsx | 303 --- .../table-category/CategoryColumnList.tsx | 516 ---- .../table-category/CategoryValueAddDialog.tsx | 228 -- .../CategoryValueEditDialog.tsx | 176 -- .../table-category/CategoryValueManager.tsx | 486 ---- .../CategoryValueManagerTree.tsx | 955 ------- frontend/components/unified/UnifiedSelect.tsx | 34 +- .../components/v2/ConditionalConfigPanel.tsx | 8 +- .../V2AggregationWidgetConfigPanel.tsx | 125 +- .../V2CategoryManagerConfigPanel.tsx | 190 +- .../V2LocationSwapSelectorConfigPanel.tsx | 4 +- .../V2SelectedItemsDetailInputConfigPanel.tsx | 6 +- frontend/constants/tableManagement.ts | 4 +- frontend/hooks/queries/useCategories.ts | 78 - .../hooks/queries/useCategoriesInfinite.ts | 43 - frontend/hooks/queries/useCodeDetail.ts | 101 + frontend/hooks/queries/useCodeInfo.ts | 89 + frontend/hooks/queries/useCodeInfoInfinite.ts | 38 + frontend/hooks/queries/useCodes.ts | 307 --- frontend/hooks/queries/useCodesInfinite.ts | 49 - frontend/hooks/queries/useValidation.ts | 46 +- frontend/hooks/useAutoFill.ts | 204 -- frontend/hooks/useCascadingDropdown.ts | 546 ---- frontend/hooks/useSelectedCategory.ts | 51 - frontend/hooks/useSelectedCodeInfo.ts | 38 + frontend/lib/api/cascadingAutoFill.ts | 231 -- frontend/lib/api/cascadingCondition.ts | 206 -- frontend/lib/api/cascadingHierarchy.ts | 317 --- frontend/lib/api/cascadingMutualExclusion.ts | 215 -- frontend/lib/api/cascadingRelation.ts | 180 -- frontend/lib/api/categoryTree.ts | 226 -- frontend/lib/api/categoryValueCascading.ts | 255 -- frontend/lib/api/codeManagement.ts | 160 +- frontend/lib/api/commonCode.ts | 409 ++- frontend/lib/api/dataflow.ts | 2 +- frontend/lib/api/entityReference.ts | 6 +- frontend/lib/api/menu.ts | 2 +- frontend/lib/api/multiConnection.ts | 8 +- frontend/lib/api/tableCategoryValue.ts | 331 --- frontend/lib/api/tableManagement.ts | 4 +- frontend/lib/caching/codeCache.ts | 6 +- .../lib/hooks/useEntityJoinOptimization.ts | 6 +- frontend/lib/queryKeys.ts | 67 +- .../CategorySelectComponent.tsx | 23 +- .../ConditionalContainerConfigPanel.tsx | 5 +- .../LocationSwapSelectorComponent.tsx | 8 +- .../LocationSwapSelectorConfigPanel.tsx | 4 +- .../domain/v2-location-swap-selector/index.ts | 2 +- .../RackStructureComponent.tsx | 36 - .../EntitySearchInputComponent.tsx | 132 +- .../EntitySearchInputConfigPanel.tsx | 262 +- .../components/entity-search-input/config.ts | 7 +- frontend/lib/registry/components/index.ts | 1 - .../components/input/use-option-loader.ts | 20 +- .../LocationSwapSelectorComponent.tsx | 8 +- .../LocationSwapSelectorConfigPanel.tsx | 4 +- .../location-swap-selector/index.ts | 2 +- .../ItemSelectionModal.tsx | 143 +- .../components/modal-repeater-table/types.ts | 3 +- .../rack-structure/RackStructureComponent.tsx | 37 - .../search/InvSearchConfigPanel.tsx | 2 +- .../SelectedItemsDetailInputComponent.tsx | 36 +- .../SelectedItemsDetailInputConfigPanel.tsx | 593 +---- .../selected-items-detail-input/types.ts | 2 +- .../SplitPanelLayoutConfigPanel.tsx | 2 +- .../SplitPanelLayout2Component.tsx | 84 - .../table-list/TableListComponent.tsx | 20 +- .../registry/components/table-list/types.ts | 2 +- .../TableSectionRenderer.tsx | 90 +- .../UniversalFormModalComponent.tsx | 232 -- .../components/universal-form-modal/config.ts | 2 +- .../modals/FieldDetailSettingsModal.tsx | 566 +--- .../modals/TableSectionSettingsModal.tsx | 94 +- .../components/universal-form-modal/types.ts | 33 +- .../AggregationWidgetConfigPanel.tsx | 39 +- .../V2CategoryManagerComponent.tsx | 266 -- .../V2CategoryManagerConfigPanel.tsx | 126 - .../V2CategoryManagerRenderer.tsx | 13 - .../components/v2-category-manager/index.ts | 37 - .../components/v2-category-manager/types.ts | 54 - .../SplitPanelLayoutConfigPanel.tsx | 2 +- .../v2-table-list/TableListComponent.tsx | 20 +- .../components/v2-table-list/types.ts | 2 +- frontend/lib/schemas/commonCode.ts | 108 +- frontend/lib/services/enhancedFormService.ts | 2 +- frontend/lib/types/multiConnection.ts | 2 +- frontend/lib/utils/buttonActions.ts | 39 +- .../lib/utils/getComponentConfigPanel.tsx | 8 +- frontend/lib/utils/layoutV2Converter.ts | 4 +- frontend/lib/utils/webTypeMapping.ts | 8 +- frontend/types/commonCode.ts | 132 +- frontend/types/screen-legacy-backup.ts | 1019 ------- frontend/types/table-management.ts | 14 +- .../2026-05-14-container-twin/index.html | 2340 ++++++++++++++++- notes/gbpark/2026-05-15-common-code-audit.md | 269 ++ .../2026-05-15-numbering-rule-clean-v2.html | 1450 ++++++++++ .../2026-05-15-numbering-rule-clean-v3.html | 1598 +++++++++++ .../2026-05-15-numbering-rule-clean.html | 1238 +++++++++ 186 files changed, 9799 insertions(+), 26330 deletions(-) delete mode 100644 backend-spring/src/main/java/com/erp/controller/CascadingAutoFillController.java delete mode 100644 backend-spring/src/main/java/com/erp/controller/CascadingConditionController.java delete mode 100644 backend-spring/src/main/java/com/erp/controller/CascadingHierarchyController.java delete mode 100644 backend-spring/src/main/java/com/erp/controller/CascadingMutualExclusionController.java delete mode 100644 backend-spring/src/main/java/com/erp/controller/CascadingRelationController.java delete mode 100644 backend-spring/src/main/java/com/erp/controller/CategoryTreeController.java delete mode 100644 backend-spring/src/main/java/com/erp/controller/CategoryValueCascadingController.java delete mode 100644 backend-spring/src/main/java/com/erp/controller/CodeMergeController.java delete mode 100644 backend-spring/src/main/java/com/erp/controller/TableCategoryValueController.java delete mode 100644 backend-spring/src/main/java/com/erp/service/CascadingAutoFillService.java delete mode 100644 backend-spring/src/main/java/com/erp/service/CascadingConditionService.java delete mode 100644 backend-spring/src/main/java/com/erp/service/CascadingHierarchyService.java delete mode 100644 backend-spring/src/main/java/com/erp/service/CascadingMutualExclusionService.java delete mode 100644 backend-spring/src/main/java/com/erp/service/CascadingRelationService.java delete mode 100644 backend-spring/src/main/java/com/erp/service/CategoryTreeService.java delete mode 100644 backend-spring/src/main/java/com/erp/service/CategoryValueCascadingService.java delete mode 100644 backend-spring/src/main/java/com/erp/service/CodeMergeService.java delete mode 100644 backend-spring/src/main/java/com/erp/service/TableCategoryValueService.java delete mode 100644 backend-spring/src/main/resources/mapper/cascadingAutoFill.xml delete mode 100644 backend-spring/src/main/resources/mapper/cascadingCondition.xml delete mode 100644 backend-spring/src/main/resources/mapper/cascadingHierarchy.xml delete mode 100644 backend-spring/src/main/resources/mapper/cascadingMutualExclusion.xml delete mode 100644 backend-spring/src/main/resources/mapper/cascadingRelation.xml delete mode 100644 backend-spring/src/main/resources/mapper/categoryTree.xml delete mode 100644 backend-spring/src/main/resources/mapper/categoryValueCascading.xml delete mode 100644 backend-spring/src/main/resources/mapper/codeMerge.xml delete mode 100644 backend-spring/src/main/resources/mapper/tableCategoryValue.xml delete mode 100644 frontend/app/(main)/admin/auto-fill/page.tsx delete mode 100644 frontend/app/(main)/admin/cascading-management/page.tsx delete mode 100644 frontend/app/(main)/admin/cascading-management/tabs/AutoFillTab.tsx delete mode 100644 frontend/app/(main)/admin/cascading-management/tabs/CascadingRelationsTab.tsx delete mode 100644 frontend/app/(main)/admin/cascading-management/tabs/CategoryValueCascadingTab.tsx delete mode 100644 frontend/app/(main)/admin/cascading-management/tabs/ConditionTab.tsx delete mode 100644 frontend/app/(main)/admin/cascading-management/tabs/HierarchyColumnTab.tsx delete mode 100644 frontend/app/(main)/admin/cascading-management/tabs/HierarchyTab.tsx delete mode 100644 frontend/app/(main)/admin/cascading-management/tabs/MutualExclusionTab.tsx delete mode 100644 frontend/app/(main)/admin/cascading-relations/page.tsx delete mode 100644 frontend/components/admin/CodeCategoryFormModal.tsx create mode 100644 frontend/components/admin/CodeInfoFormModal.tsx rename frontend/components/admin/{CategoryItem.tsx => CodeInfoItem.tsx} (50%) rename frontend/components/admin/{CodeCategoryPanel.tsx => CodeInfoPanel.tsx} (51%) delete mode 100644 frontend/components/common/CascadingDropdown.tsx delete mode 100644 frontend/components/table-category/AddCategoryColumnDialog.tsx delete mode 100644 frontend/components/table-category/CategoryColumnList.tsx delete mode 100644 frontend/components/table-category/CategoryValueAddDialog.tsx delete mode 100644 frontend/components/table-category/CategoryValueEditDialog.tsx delete mode 100644 frontend/components/table-category/CategoryValueManager.tsx delete mode 100644 frontend/components/table-category/CategoryValueManagerTree.tsx delete mode 100644 frontend/hooks/queries/useCategories.ts delete mode 100644 frontend/hooks/queries/useCategoriesInfinite.ts create mode 100644 frontend/hooks/queries/useCodeDetail.ts create mode 100644 frontend/hooks/queries/useCodeInfo.ts create mode 100644 frontend/hooks/queries/useCodeInfoInfinite.ts delete mode 100644 frontend/hooks/queries/useCodes.ts delete mode 100644 frontend/hooks/queries/useCodesInfinite.ts delete mode 100644 frontend/hooks/useAutoFill.ts delete mode 100644 frontend/hooks/useCascadingDropdown.ts delete mode 100644 frontend/hooks/useSelectedCategory.ts create mode 100644 frontend/hooks/useSelectedCodeInfo.ts delete mode 100644 frontend/lib/api/cascadingAutoFill.ts delete mode 100644 frontend/lib/api/cascadingCondition.ts delete mode 100644 frontend/lib/api/cascadingHierarchy.ts delete mode 100644 frontend/lib/api/cascadingMutualExclusion.ts delete mode 100644 frontend/lib/api/cascadingRelation.ts delete mode 100644 frontend/lib/api/categoryTree.ts delete mode 100644 frontend/lib/api/categoryValueCascading.ts delete mode 100644 frontend/lib/api/tableCategoryValue.ts delete mode 100644 frontend/lib/registry/components/v2-category-manager/V2CategoryManagerComponent.tsx delete mode 100644 frontend/lib/registry/components/v2-category-manager/V2CategoryManagerConfigPanel.tsx delete mode 100644 frontend/lib/registry/components/v2-category-manager/V2CategoryManagerRenderer.tsx delete mode 100644 frontend/lib/registry/components/v2-category-manager/index.ts delete mode 100644 frontend/lib/registry/components/v2-category-manager/types.ts delete mode 100644 frontend/types/screen-legacy-backup.ts create mode 100644 notes/gbpark/2026-05-15-common-code-audit.md create mode 100644 notes/gbpark/2026-05-15-numbering-rule-clean-v2.html create mode 100644 notes/gbpark/2026-05-15-numbering-rule-clean-v3.html create mode 100644 notes/gbpark/2026-05-15-numbering-rule-clean.html diff --git a/backend-spring/src/main/java/com/erp/controller/CascadingAutoFillController.java b/backend-spring/src/main/java/com/erp/controller/CascadingAutoFillController.java deleted file mode 100644 index 0c1d21cf..00000000 --- a/backend-spring/src/main/java/com/erp/controller/CascadingAutoFillController.java +++ /dev/null @@ -1,125 +0,0 @@ -package com.erp.controller; - -import com.erp.dto.ApiResponse; -import com.erp.service.CascadingAutoFillService; -import lombok.RequiredArgsConstructor; -import lombok.extern.slf4j.Slf4j; -import org.springframework.http.HttpStatus; -import org.springframework.http.ResponseEntity; -import org.springframework.web.bind.annotation.*; -import java.util.*; - -@RestController -@RequestMapping("/api/cascading-auto-fill") -@RequiredArgsConstructor -@Slf4j -public class CascadingAutoFillController { - private final CascadingAutoFillService cascadingAutoFillService; - - // Pipeline api_test compatibility alias - @GetMapping("/list") - public ResponseEntity>> getGroupListAlias( - @RequestAttribute("company_code") String companyCode, - @RequestParam Map params) { - params.put("company_code", companyCode); - return ResponseEntity.ok(ApiResponse.success(cascadingAutoFillService.getCascadingAutoFillGroupList(params))); - } - - @GetMapping("/groups") - public ResponseEntity>> getGroupList( - @RequestAttribute("company_code") String companyCode, - @RequestParam Map params) { - params.put("company_code", companyCode); - return ResponseEntity.ok(ApiResponse.success(cascadingAutoFillService.getCascadingAutoFillGroupList(params))); - } - - @GetMapping("/groups/{groupCode}") - public ResponseEntity>> getGroupDetail( - @RequestAttribute("company_code") String companyCode, - @PathVariable String groupCode) { - Map params = new HashMap<>(); - params.put("company_code", companyCode); - params.put("group_code", groupCode); - Map result = cascadingAutoFillService.getCascadingAutoFillGroupDetail(params); - if (result == null) { - return ResponseEntity.status(HttpStatus.NOT_FOUND) - .body(ApiResponse.error("자동 입력 그룹을 찾을 수 없습니다.")); - } - return ResponseEntity.ok(ApiResponse.success(result)); - } - - @PostMapping("/groups") - public ResponseEntity>> createGroup( - @RequestAttribute("company_code") String companyCode, - @RequestBody Map body) { - body.put("company_code", companyCode); - return ResponseEntity.status(HttpStatus.CREATED) - .body(ApiResponse.success(cascadingAutoFillService.insertCascadingAutoFillGroup(body))); - } - - @PutMapping("/groups/{groupCode}") - public ResponseEntity>> updateGroup( - @RequestAttribute("company_code") String companyCode, - @PathVariable String groupCode, - @RequestBody Map body) { - body.put("company_code", companyCode); - body.put("group_code", groupCode); - Map result = cascadingAutoFillService.updateCascadingAutoFillGroup(body); - if (result == null) { - return ResponseEntity.status(HttpStatus.NOT_FOUND) - .body(ApiResponse.error("자동 입력 그룹을 찾을 수 없습니다.")); - } - return ResponseEntity.ok(ApiResponse.success(result)); - } - - @DeleteMapping("/groups/{groupCode}") - public ResponseEntity> deleteGroup( - @RequestAttribute("company_code") String companyCode, - @PathVariable String groupCode) { - Map params = new HashMap<>(); - params.put("company_code", companyCode); - params.put("group_code", groupCode); - boolean deleted = cascadingAutoFillService.deleteCascadingAutoFillGroup(params); - if (!deleted) { - return ResponseEntity.status(HttpStatus.NOT_FOUND) - .body(ApiResponse.error("자동 입력 그룹을 찾을 수 없습니다.")); - } - return ResponseEntity.ok(ApiResponse.success(null)); - } - - @GetMapping("/options/{groupCode}") - public ResponseEntity>>> getMasterOptions( - @RequestAttribute("company_code") String companyCode, - @PathVariable String groupCode) { - Map params = new HashMap<>(); - params.put("company_code", companyCode); - params.put("group_code", groupCode); - List> result = cascadingAutoFillService.getAutoFillMasterOptions(params); - if (result == null) { - return ResponseEntity.status(HttpStatus.NOT_FOUND) - .body(ApiResponse.error("자동 입력 그룹을 찾을 수 없습니다.")); - } - return ResponseEntity.ok(ApiResponse.success(result)); - } - - @GetMapping("/data/{groupCode}") - public ResponseEntity>> getAutoFillData( - @RequestAttribute("company_code") String companyCode, - @PathVariable String groupCode, - @RequestParam(required = false) String masterValue) { - if (masterValue == null || masterValue.isBlank()) { - return ResponseEntity.status(HttpStatus.BAD_REQUEST) - .body(ApiResponse.error("masterValue 파라미터가 필요합니다.")); - } - Map params = new HashMap<>(); - params.put("company_code", companyCode); - params.put("group_code", groupCode); - params.put("master_value", masterValue); - Map result = cascadingAutoFillService.getAutoFillData(params); - if (result == null) { - return ResponseEntity.status(HttpStatus.NOT_FOUND) - .body(ApiResponse.error("자동 입력 그룹을 찾을 수 없습니다.")); - } - return ResponseEntity.ok(ApiResponse.success(result)); - } -} diff --git a/backend-spring/src/main/java/com/erp/controller/CascadingConditionController.java b/backend-spring/src/main/java/com/erp/controller/CascadingConditionController.java deleted file mode 100644 index 39894d61..00000000 --- a/backend-spring/src/main/java/com/erp/controller/CascadingConditionController.java +++ /dev/null @@ -1,81 +0,0 @@ -package com.erp.controller; - -import com.erp.dto.ApiResponse; -import com.erp.service.CascadingConditionService; -import lombok.RequiredArgsConstructor; -import lombok.extern.slf4j.Slf4j; -import org.springframework.http.ResponseEntity; -import org.springframework.web.bind.annotation.*; -import java.util.*; - -@RestController -@RequestMapping("/api/cascading-condition") -@RequiredArgsConstructor -@Slf4j -public class CascadingConditionController { - private final CascadingConditionService cascadingConditionService; - - @GetMapping("/list") - public ResponseEntity>> getCascadingConditionListAlias( - @RequestAttribute("company_code") String companyCode, - @RequestParam Map params) { - params.put("company_code", companyCode); - return ResponseEntity.ok(ApiResponse.success(cascadingConditionService.getCascadingConditionList(params))); - } - - @GetMapping - public ResponseEntity>> getCascadingConditionList( - @RequestAttribute("company_code") String companyCode, - @RequestParam Map params) { - params.put("company_code", companyCode); - return ResponseEntity.ok(ApiResponse.success(cascadingConditionService.getCascadingConditionList(params))); - } - - @GetMapping("/filtered-options/{relationCode}") - public ResponseEntity>> getFilteredOptions( - @RequestAttribute("company_code") String companyCode, - @PathVariable String relationCode, - @RequestParam Map params) { - params.put("company_code", companyCode); - params.put("relation_code", relationCode); - return ResponseEntity.ok(ApiResponse.success(cascadingConditionService.getFilteredOptions(params))); - } - - @GetMapping("/{conditionId}") - public ResponseEntity>> getCascadingConditionInfo( - @RequestAttribute("company_code") String companyCode, - @PathVariable Long conditionId) { - Map params = new HashMap<>(); - params.put("company_code", companyCode); - params.put("condition_id", conditionId); - return ResponseEntity.ok(ApiResponse.success(cascadingConditionService.getCascadingConditionInfo(params))); - } - - @PostMapping - public ResponseEntity>> insertCascadingCondition( - @RequestAttribute("company_code") String companyCode, - @RequestBody Map body) { - body.put("company_code", companyCode); - return ResponseEntity.ok(ApiResponse.success(cascadingConditionService.insertCascadingCondition(body))); - } - - @PutMapping("/{conditionId}") - public ResponseEntity>> updateCascadingCondition( - @RequestAttribute("company_code") String companyCode, - @PathVariable Long conditionId, - @RequestBody Map body) { - body.put("company_code", companyCode); - body.put("condition_id", conditionId); - return ResponseEntity.ok(ApiResponse.success(cascadingConditionService.updateCascadingCondition(body))); - } - - @DeleteMapping("/{conditionId}") - public ResponseEntity>> deleteCascadingCondition( - @RequestAttribute("company_code") String companyCode, - @PathVariable Long conditionId) { - Map params = new HashMap<>(); - params.put("company_code", companyCode); - params.put("condition_id", conditionId); - return ResponseEntity.ok(ApiResponse.success(cascadingConditionService.deleteCascadingCondition(params))); - } -} diff --git a/backend-spring/src/main/java/com/erp/controller/CascadingHierarchyController.java b/backend-spring/src/main/java/com/erp/controller/CascadingHierarchyController.java deleted file mode 100644 index 09fe1383..00000000 --- a/backend-spring/src/main/java/com/erp/controller/CascadingHierarchyController.java +++ /dev/null @@ -1,157 +0,0 @@ -package com.erp.controller; - -import com.erp.dto.ApiResponse; -import com.erp.service.CascadingHierarchyService; -import lombok.RequiredArgsConstructor; -import lombok.extern.slf4j.Slf4j; -import org.springframework.http.HttpStatus; -import org.springframework.http.ResponseEntity; -import org.springframework.web.bind.annotation.*; -import java.util.*; - -@RestController -@RequestMapping("/api/cascading-hierarchy") -@RequiredArgsConstructor -@Slf4j -public class CascadingHierarchyController { - private final CascadingHierarchyService cascadingHierarchyService; - - // Pipeline api_test compatibility alias - @GetMapping("/list") - public ResponseEntity>> getGroupListAlias( - @RequestAttribute("company_code") String companyCode, - @RequestParam Map params) { - params.put("company_code", companyCode); - return ResponseEntity.ok(ApiResponse.success(cascadingHierarchyService.getCascadingHierarchyGroupList(params))); - } - - @GetMapping - public ResponseEntity>> getGroupList( - @RequestAttribute("company_code") String companyCode, - @RequestParam Map params) { - params.put("company_code", companyCode); - return ResponseEntity.ok(ApiResponse.success(cascadingHierarchyService.getCascadingHierarchyGroupList(params))); - } - - @GetMapping("/{groupCode}") - public ResponseEntity>> getGroupDetail( - @RequestAttribute("company_code") String companyCode, - @PathVariable String groupCode) { - Map params = new HashMap<>(); - params.put("company_code", companyCode); - params.put("group_code", groupCode); - Map result = cascadingHierarchyService.getCascadingHierarchyGroupDetail(params); - if (result == null) { - return ResponseEntity.status(HttpStatus.NOT_FOUND) - .body(ApiResponse.error("계층 그룹을 찾을 수 없습니다.")); - } - return ResponseEntity.ok(ApiResponse.success(result)); - } - - @PostMapping - public ResponseEntity>> createGroup( - @RequestAttribute("company_code") String companyCode, - @RequestAttribute(value = "user_id", required = false) String userId, - @RequestBody Map body) { - body.put("company_code", companyCode); - if (userId != null) body.put("user_id", userId); - return ResponseEntity.status(HttpStatus.CREATED) - .body(ApiResponse.success(cascadingHierarchyService.insertCascadingHierarchyGroup(body))); - } - - @PutMapping("/{groupCode}") - public ResponseEntity>> updateGroup( - @RequestAttribute("company_code") String companyCode, - @RequestAttribute(value = "user_id", required = false) String userId, - @PathVariable String groupCode, - @RequestBody Map body) { - body.put("company_code", companyCode); - body.put("group_code", groupCode); - if (userId != null) body.put("user_id", userId); - Map result = cascadingHierarchyService.updateCascadingHierarchyGroup(body); - if (result == null) { - return ResponseEntity.status(HttpStatus.NOT_FOUND) - .body(ApiResponse.error("계층 그룹을 찾을 수 없습니다.")); - } - return ResponseEntity.ok(ApiResponse.success(result)); - } - - @DeleteMapping("/{groupCode}") - public ResponseEntity> deleteGroup( - @RequestAttribute("company_code") String companyCode, - @PathVariable String groupCode) { - Map params = new HashMap<>(); - params.put("company_code", companyCode); - params.put("group_code", groupCode); - boolean deleted = cascadingHierarchyService.deleteCascadingHierarchyGroup(params); - if (!deleted) { - return ResponseEntity.status(HttpStatus.NOT_FOUND) - .body(ApiResponse.error("계층 그룹을 찾을 수 없습니다.")); - } - return ResponseEntity.ok(ApiResponse.success(null)); - } - - @PostMapping("/{groupCode}/levels") - public ResponseEntity>> addLevel( - @RequestAttribute("company_code") String companyCode, - @PathVariable String groupCode, - @RequestBody Map body) { - body.put("company_code", companyCode); - body.put("group_code", groupCode); - Map result = cascadingHierarchyService.addCascadingHierarchyLevel(body); - if (result == null) { - return ResponseEntity.status(HttpStatus.NOT_FOUND) - .body(ApiResponse.error("계층 그룹을 찾을 수 없습니다.")); - } - return ResponseEntity.status(HttpStatus.CREATED).body(ApiResponse.success(result)); - } - - @PutMapping("/levels/{levelId}") - public ResponseEntity>> updateLevel( - @RequestAttribute("company_code") String companyCode, - @PathVariable Long levelId, - @RequestBody Map body) { - body.put("company_code", companyCode); - body.put("level_id", levelId); - Map result = cascadingHierarchyService.updateCascadingHierarchyLevel(body); - if (result == null) { - return ResponseEntity.status(HttpStatus.NOT_FOUND) - .body(ApiResponse.error("레벨을 찾을 수 없습니다.")); - } - return ResponseEntity.ok(ApiResponse.success(result)); - } - - @DeleteMapping("/levels/{levelId}") - public ResponseEntity> deleteLevel( - @RequestAttribute("company_code") String companyCode, - @PathVariable Long levelId) { - Map params = new HashMap<>(); - params.put("company_code", companyCode); - params.put("level_id", levelId); - boolean deleted = cascadingHierarchyService.deleteCascadingHierarchyLevel(params); - if (!deleted) { - return ResponseEntity.status(HttpStatus.NOT_FOUND) - .body(ApiResponse.error("레벨을 찾을 수 없습니다.")); - } - return ResponseEntity.ok(ApiResponse.success(null)); - } - - @GetMapping("/{groupCode}/options/{levelOrder}") - public ResponseEntity>> getLevelOptions( - @RequestAttribute("company_code") String companyCode, - @PathVariable String groupCode, - @PathVariable Integer levelOrder, - @RequestParam(required = false) String parentValue) { - Map params = new HashMap<>(); - params.put("company_code", companyCode); - params.put("group_code", groupCode); - params.put("level_order", levelOrder); - if (parentValue != null) params.put("parent_value", parentValue); - Map result = cascadingHierarchyService.getLevelOptions(params); - if (result == null) { - return ResponseEntity.status(HttpStatus.NOT_FOUND) - .body(ApiResponse.error("레벨을 찾을 수 없습니다.")); - } - return ResponseEntity.ok(ApiResponse.success(result)); - } -} diff --git a/backend-spring/src/main/java/com/erp/controller/CascadingMutualExclusionController.java b/backend-spring/src/main/java/com/erp/controller/CascadingMutualExclusionController.java deleted file mode 100644 index 739afd4d..00000000 --- a/backend-spring/src/main/java/com/erp/controller/CascadingMutualExclusionController.java +++ /dev/null @@ -1,121 +0,0 @@ -package com.erp.controller; - -import com.erp.dto.ApiResponse; -import com.erp.service.CascadingMutualExclusionService; -import lombok.RequiredArgsConstructor; -import lombok.extern.slf4j.Slf4j; -import org.springframework.http.ResponseEntity; -import org.springframework.web.bind.annotation.*; -import java.util.*; - -/** - * 상호 배제 API - * Node.js: app.use("/api/cascading-mutual-exclusion", cascadingMutualExclusionRoutes) - */ -@RestController -@RequestMapping("/api/cascading-mutual-exclusion") -@RequiredArgsConstructor -@Slf4j -public class CascadingMutualExclusionController { - private final CascadingMutualExclusionService cascadingMutualExclusionService; - - /** GET /list — 목록 조회 (alias) */ - @GetMapping("/list") - public ResponseEntity>> getCascadingMutualExclusionListAlias( - @RequestAttribute("company_code") String companyCode, - @RequestParam Map params) { - params.put("company_code", companyCode); - return ResponseEntity.ok(ApiResponse.success( - cascadingMutualExclusionService.getCascadingMutualExclusionList(params))); - } - - /** GET / — 목록 조회 */ - @GetMapping - public ResponseEntity>> getCascadingMutualExclusionList( - @RequestAttribute("company_code") String companyCode, - @RequestParam Map params) { - params.put("company_code", companyCode); - return ResponseEntity.ok(ApiResponse.success( - cascadingMutualExclusionService.getCascadingMutualExclusionList(params))); - } - - /** GET /{exclusionId} — 상세 조회 */ - @GetMapping("/{exclusionId}") - public ResponseEntity>> getCascadingMutualExclusionInfo( - @RequestAttribute("company_code") String companyCode, - @PathVariable Long exclusionId) { - Map params = new LinkedHashMap<>(); - params.put("company_code", companyCode); - params.put("id", exclusionId); - return ResponseEntity.ok(ApiResponse.success( - cascadingMutualExclusionService.getCascadingMutualExclusionInfo(params))); - } - - /** POST / — 생성 */ - @PostMapping - public ResponseEntity>> insertCascadingMutualExclusion( - @RequestAttribute("company_code") String companyCode, - @RequestBody Map body) { - body.put("company_code", companyCode); - return ResponseEntity.ok(ApiResponse.success( - cascadingMutualExclusionService.insertCascadingMutualExclusion(body))); - } - - /** PUT /{exclusionId} — 수정 */ - @PutMapping("/{exclusionId}") - public ResponseEntity>> updateCascadingMutualExclusion( - @RequestAttribute("company_code") String companyCode, - @PathVariable Long exclusionId, - @RequestBody Map body) { - body.put("company_code", companyCode); - body.put("id", exclusionId); - return ResponseEntity.ok(ApiResponse.success( - cascadingMutualExclusionService.updateCascadingMutualExclusion(body))); - } - - /** DELETE /{exclusionId} — 하드 삭제 */ - @DeleteMapping("/{exclusionId}") - public ResponseEntity>> deleteCascadingMutualExclusion( - @RequestAttribute("company_code") String companyCode, - @PathVariable Long exclusionId) { - Map params = new LinkedHashMap<>(); - params.put("company_code", companyCode); - params.put("id", exclusionId); - return ResponseEntity.ok(ApiResponse.success( - cascadingMutualExclusionService.deleteCascadingMutualExclusion(params))); - } - - /** - * POST /validate/{exclusionCode} — 상호 배제 검증 - * body: { "field_values": { "field_a": "val1", "field_b": "val1" } } - */ - @PostMapping("/validate/{exclusionCode}") - public ResponseEntity>> validateCascadingMutualExclusion( - @RequestAttribute("company_code") String companyCode, - @PathVariable String exclusionCode, - @RequestBody Map body) { - body.put("company_code", companyCode); - body.put("code", exclusionCode); - return ResponseEntity.ok(ApiResponse.success( - cascadingMutualExclusionService.validateCascadingMutualExclusion(body))); - } - - /** - * GET /options/{exclusionCode} — 배제 옵션 조회 - * query: selectedValues (콤마 구분된 이미 선택된 값들) - */ - @GetMapping("/options/{exclusionCode}") - public ResponseEntity>>> getExcludedOptions( - @RequestAttribute("company_code") String companyCode, - @PathVariable String exclusionCode, - @RequestParam(required = false) String currentField, - @RequestParam(required = false) String selectedValues) { - Map params = new LinkedHashMap<>(); - params.put("company_code", companyCode); - params.put("code", exclusionCode); - params.put("current_field", currentField); - params.put("selected_values", selectedValues); - return ResponseEntity.ok(ApiResponse.success( - cascadingMutualExclusionService.getExcludedOptions(params))); - } -} diff --git a/backend-spring/src/main/java/com/erp/controller/CascadingRelationController.java b/backend-spring/src/main/java/com/erp/controller/CascadingRelationController.java deleted file mode 100644 index ec6dd787..00000000 --- a/backend-spring/src/main/java/com/erp/controller/CascadingRelationController.java +++ /dev/null @@ -1,139 +0,0 @@ -package com.erp.controller; - -import com.erp.dto.ApiResponse; -import com.erp.service.CascadingRelationService; -import lombok.RequiredArgsConstructor; -import lombok.extern.slf4j.Slf4j; -import org.springframework.http.ResponseEntity; -import org.springframework.web.bind.annotation.*; -import java.util.*; - -/** - * 연쇄 관계 API - * Node.js: app.use("/api/cascading-relation", cascadingRelationRoutes) - */ -@RestController -@RequestMapping("/api/cascading-relation") -@RequiredArgsConstructor -@Slf4j -public class CascadingRelationController { - private final CascadingRelationService cascadingRelationService; - - /** GET /api/cascading-relation/list — 목록 조회 (alias) */ - @GetMapping("/list") - public ResponseEntity>> getCascadingRelationListAlias( - @RequestAttribute("company_code") String companyCode, - @RequestParam Map params) { - params.put("company_code", companyCode); - return ResponseEntity.ok(ApiResponse.success( - cascadingRelationService.getCascadingRelationList(params))); - } - - /** GET /api/cascading-relation — 목록 조회 */ - @GetMapping - public ResponseEntity>> getCascadingRelationList( - @RequestAttribute("company_code") String companyCode, - @RequestParam Map params) { - params.put("company_code", companyCode); - return ResponseEntity.ok(ApiResponse.success( - cascadingRelationService.getCascadingRelationList(params))); - } - - /** GET /api/cascading-relation/{id} — 상세 조회 */ - @GetMapping("/{id}") - public ResponseEntity>> getCascadingRelationInfo( - @RequestAttribute("company_code") String companyCode, - @PathVariable Long id) { - Map params = new LinkedHashMap<>(); - params.put("company_code", companyCode); - params.put("id", id); - return ResponseEntity.ok(ApiResponse.success( - cascadingRelationService.getCascadingRelationInfo(params))); - } - - /** GET /api/cascading-relation/code/{code} — 코드로 단건 조회 */ - @GetMapping("/code/{code}") - public ResponseEntity>> getCascadingRelationByCode( - @RequestAttribute("company_code") String companyCode, - @PathVariable String code) { - Map params = new LinkedHashMap<>(); - params.put("company_code", companyCode); - params.put("code", code); - return ResponseEntity.ok(ApiResponse.success( - cascadingRelationService.getCascadingRelationByCode(params))); - } - - /** - * GET /api/cascading-relation/parent-options/{code} - * 부모 옵션 조회 (parent_table 동적 쿼리) - */ - @GetMapping("/parent-options/{code}") - public ResponseEntity>>> getParentOptions( - @RequestAttribute("company_code") String companyCode, - @PathVariable String code) { - Map params = new LinkedHashMap<>(); - params.put("company_code", companyCode); - params.put("code", code); - return ResponseEntity.ok(ApiResponse.success( - cascadingRelationService.getParentOptions(params))); - } - - /** - * GET /api/cascading-relation/options/{code}?parentValue=&parentValues= - * 연쇄 자식 옵션 조회 (child_table 동적 쿼리) - */ - @GetMapping("/options/{code}") - public ResponseEntity>>> getCascadingOptions( - @RequestAttribute("company_code") String companyCode, - @PathVariable String code, - @RequestParam(required = false) String parentValue, - @RequestParam(required = false) String parentValues) { - Map params = new LinkedHashMap<>(); - params.put("company_code", companyCode); - params.put("code", code); - params.put("parent_value", parentValue); - params.put("parent_values", parentValues); - return ResponseEntity.ok(ApiResponse.success( - cascadingRelationService.getCascadingOptions(params))); - } - - /** POST /api/cascading-relation — 생성 */ - @PostMapping - public ResponseEntity>> insertCascadingRelation( - @RequestAttribute("company_code") String companyCode, - @RequestAttribute(value = "user_id", required = false) String userId, - @RequestBody Map body) { - body.put("company_code", companyCode); - body.put("user_id", userId != null ? userId : "system"); - return ResponseEntity.ok(ApiResponse.success( - cascadingRelationService.insertCascadingRelation(body))); - } - - /** PUT /api/cascading-relation/{id} — 수정 */ - @PutMapping("/{id}") - public ResponseEntity>> updateCascadingRelation( - @RequestAttribute("company_code") String companyCode, - @RequestAttribute(value = "user_id", required = false) String userId, - @PathVariable Long id, - @RequestBody Map body) { - body.put("company_code", companyCode); - body.put("user_id", userId != null ? userId : "system"); - body.put("id", id); - return ResponseEntity.ok(ApiResponse.success( - cascadingRelationService.updateCascadingRelation(body))); - } - - /** DELETE /api/cascading-relation/{id} — 소프트 삭제 (is_active = 'N') */ - @DeleteMapping("/{id}") - public ResponseEntity>> deleteCascadingRelation( - @RequestAttribute("company_code") String companyCode, - @RequestAttribute(value = "user_id", required = false) String userId, - @PathVariable Long id) { - Map params = new LinkedHashMap<>(); - params.put("company_code", companyCode); - params.put("user_id", userId != null ? userId : "system"); - params.put("id", id); - return ResponseEntity.ok(ApiResponse.success( - cascadingRelationService.deleteCascadingRelation(params))); - } -} diff --git a/backend-spring/src/main/java/com/erp/controller/CategoryTreeController.java b/backend-spring/src/main/java/com/erp/controller/CategoryTreeController.java deleted file mode 100644 index e98b38dc..00000000 --- a/backend-spring/src/main/java/com/erp/controller/CategoryTreeController.java +++ /dev/null @@ -1,191 +0,0 @@ -package com.erp.controller; - -import com.erp.dto.ApiResponse; -import com.erp.service.CategoryTreeService; -import lombok.RequiredArgsConstructor; -import lombok.extern.slf4j.Slf4j; -import org.springframework.http.ResponseEntity; -import org.springframework.web.bind.annotation.*; - -import java.util.List; -import java.util.Map; - -@Slf4j -@RestController -@RequestMapping("/api/category-tree") -@RequiredArgsConstructor -public class CategoryTreeController { - - private final CategoryTreeService categoryTreeService; - - /** - * GET /api/category-tree/test/all-category-keys - * 전체 카테고리 키 목록 조회 (모든 테이블.컬럼 조합) - * 주의: /test/{tableName}/{columnName} 보다 먼저 매핑되어야 함 - */ - @GetMapping("/test/all-category-keys") - public ResponseEntity>>> getCategoryTreeKeyList( - @RequestAttribute("company_code") String companyCode) { - - List> keys = categoryTreeService.getCategoryTreeKeyList(companyCode); - return ResponseEntity.ok(ApiResponse.success(keys)); - } - - /** - * GET /api/category-tree/test/{tableName}/{columnName} - * 카테고리 트리 조회 - */ - @GetMapping("/test/{tableName}/{columnName}") - public ResponseEntity>>> getCategoryTreeList( - @RequestAttribute("company_code") String companyCode, - @PathVariable String tableName, - @PathVariable String columnName) { - - List> tree = categoryTreeService.getCategoryTreeList(companyCode, tableName, columnName); - return ResponseEntity.ok(ApiResponse.success(tree)); - } - - /** - * GET /api/category-tree/test/{tableName}/{columnName}/flat - * 카테고리 플랫 리스트 조회 - */ - @GetMapping("/test/{tableName}/{columnName}/flat") - public ResponseEntity>>> getCategoryTreeFlatList( - @RequestAttribute("company_code") String companyCode, - @PathVariable String tableName, - @PathVariable String columnName) { - - List> list = categoryTreeService.getCategoryTreeFlatList(companyCode, tableName, columnName); - return ResponseEntity.ok(ApiResponse.success(list)); - } - - /** - * GET /api/category-tree/test/value/{valueId} - * 카테고리 값 단건 조회 - */ - @GetMapping("/test/value/{valueId}") - public ResponseEntity>> getCategoryTreeInfo( - @RequestAttribute("company_code") String companyCode, - @PathVariable int valueId) { - - Map value = categoryTreeService.getCategoryTreeInfo(companyCode, valueId); - if (value == null) { - return ResponseEntity.status(404).body(ApiResponse.error("카테고리 값을 찾을 수 없습니다")); - } - return ResponseEntity.ok(ApiResponse.success(value)); - } - - /** - * POST /api/category-tree/test/value - * 카테고리 값 생성 - */ - @PostMapping("/test/value") - public ResponseEntity>> insertCategoryTree( - @RequestAttribute("company_code") String userCompanyCode, - @RequestAttribute("user_id") String userId, - @RequestBody Map body) { - - if (body.get("table_name") == null || body.get("column_name") == null - || body.get("value_code") == null || body.get("value_label") == null) { - return ResponseEntity.badRequest() - .body(ApiResponse.error("tableName, columnName, valueCode, valueLabel은 필수입니다")); - } - - // 최고 관리자(*) 는 targetCompanyCode 로 회사 코드 오버라이드 가능 - String companyCode = userCompanyCode; - String targetCompanyCode = (String) body.get("target_company_code"); - if (targetCompanyCode != null && "*".equals(userCompanyCode)) { - companyCode = targetCompanyCode; - } - - try { - Map value = categoryTreeService.insertCategoryTree(body, companyCode, userId); - return ResponseEntity.ok(ApiResponse.success(value)); - } catch (IllegalArgumentException e) { - return ResponseEntity.badRequest().body(ApiResponse.error(e.getMessage())); - } catch (Exception e) { - log.error("카테고리 값 생성 오류", e); - return ResponseEntity.status(500).body(ApiResponse.error(e.getMessage())); - } - } - - /** - * PUT /api/category-tree/test/value/{valueId} - * 카테고리 값 수정 - */ - @PutMapping("/test/value/{valueId}") - public ResponseEntity>> updateCategoryTree( - @RequestAttribute("company_code") String companyCode, - @RequestAttribute("user_id") String userId, - @PathVariable int valueId, - @RequestBody Map body) { - - try { - Map value = categoryTreeService.updateCategoryTree(companyCode, valueId, body, userId); - if (value == null) { - return ResponseEntity.status(404).body(ApiResponse.error("카테고리 값을 찾을 수 없습니다")); - } - return ResponseEntity.ok(ApiResponse.success(value)); - } catch (IllegalArgumentException e) { - return ResponseEntity.badRequest().body(ApiResponse.error(e.getMessage())); - } catch (Exception e) { - log.error("카테고리 값 수정 오류", e); - return ResponseEntity.status(500).body(ApiResponse.error(e.getMessage())); - } - } - - /** - * GET /api/category-tree/test/value/{valueId}/can-delete - * 카테고리 값 삭제 가능 여부 사전 확인 - */ - @GetMapping("/test/value/{valueId}/can-delete") - public ResponseEntity>> checkCanDelete( - @RequestAttribute("company_code") String companyCode, - @PathVariable int valueId) { - - Map result = categoryTreeService.checkCanDelete(companyCode, valueId); - return ResponseEntity.ok(ApiResponse.success(result)); - } - - /** - * DELETE /api/category-tree/test/value/{valueId} - * 카테고리 값 삭제 - */ - @DeleteMapping("/test/value/{valueId}") - public ResponseEntity> deleteCategoryTree( - @RequestAttribute("company_code") String companyCode, - @PathVariable int valueId) { - - try { - boolean deleted = categoryTreeService.deleteCategoryTree(companyCode, valueId); - if (!deleted) { - return ResponseEntity.status(404).body(ApiResponse.error("카테고리 값을 찾을 수 없습니다")); - } - return ResponseEntity.ok(ApiResponse.success(null, "삭제되었습니다")); - } catch (IllegalStateException e) { - String msg = e.getMessage(); - if (msg != null && msg.startsWith("VALIDATION:")) { - return ResponseEntity.badRequest() - .body(ApiResponse.error(msg.substring("VALIDATION:".length()))); - } - log.error("카테고리 값 삭제 오류", e); - return ResponseEntity.status(500).body(ApiResponse.error(msg)); - } catch (Exception e) { - log.error("카테고리 값 삭제 오류", e); - return ResponseEntity.status(500).body(ApiResponse.error(e.getMessage())); - } - } - - /** - * GET /api/category-tree/test/columns/{tableName} - * 테이블의 카테고리 컬럼 목록 조회 - */ - @GetMapping("/test/columns/{tableName}") - public ResponseEntity>>> getCategoryTreeColumnList( - @RequestAttribute("company_code") String companyCode, - @PathVariable String tableName) { - - List> columns = categoryTreeService.getCategoryTreeColumnList(companyCode, tableName); - return ResponseEntity.ok(ApiResponse.success(columns)); - } -} diff --git a/backend-spring/src/main/java/com/erp/controller/CategoryValueCascadingController.java b/backend-spring/src/main/java/com/erp/controller/CategoryValueCascadingController.java deleted file mode 100644 index 20ef17c9..00000000 --- a/backend-spring/src/main/java/com/erp/controller/CategoryValueCascadingController.java +++ /dev/null @@ -1,142 +0,0 @@ -package com.erp.controller; - -import com.erp.dto.ApiResponse; -import com.erp.service.CategoryValueCascadingService; -import lombok.RequiredArgsConstructor; -import lombok.extern.slf4j.Slf4j; -import org.springframework.http.ResponseEntity; -import org.springframework.web.bind.annotation.*; -import java.util.*; - -@RestController -@RequestMapping("/api/category-value-cascading") -@RequiredArgsConstructor -@Slf4j -public class CategoryValueCascadingController { - private final CategoryValueCascadingService categoryValueCascadingService; - - /** GET /groups → 그룹 목록 조회 */ - @GetMapping("/groups") - public ResponseEntity>> getCategoryValueCascadingGroupList( - @RequestAttribute("company_code") String companyCode, - @RequestParam Map params) { - params.put("company_code", companyCode); - return ResponseEntity.ok(ApiResponse.success(categoryValueCascadingService.getCategoryValueCascadingGroupList(params))); - } - - /** GET /groups/{groupId} → 그룹 상세 조회 (매핑 포함) */ - @GetMapping("/groups/{groupId}") - public ResponseEntity>> getCategoryValueCascadingGroupInfo( - @RequestAttribute("company_code") String companyCode, - @PathVariable Long groupId) { - Map params = new HashMap<>(); - params.put("company_code", companyCode); - params.put("group_id", groupId); - Map result = categoryValueCascadingService.getCategoryValueCascadingGroupInfo(params); - if (result == null) { - return ResponseEntity.status(404).body(ApiResponse.error("카테고리 값 연쇄관계 그룹을 찾을 수 없습니다.")); - } - return ResponseEntity.ok(ApiResponse.success(result)); - } - - /** GET /code/{code} → 관계 코드로 조회 */ - @GetMapping("/code/{code}") - public ResponseEntity>> getCategoryValueCascadingGroupByCode( - @RequestAttribute("company_code") String companyCode, - @PathVariable String code) { - Map params = new HashMap<>(); - params.put("company_code", companyCode); - params.put("code", code); - Map result = categoryValueCascadingService.getCategoryValueCascadingGroupByCode(params); - if (result == null) { - return ResponseEntity.status(404).body(ApiResponse.error("카테고리 값 연쇄관계를 찾을 수 없습니다.")); - } - return ResponseEntity.ok(ApiResponse.success(result)); - } - - /** POST /groups → 그룹 생성 */ - @PostMapping("/groups") - public ResponseEntity>> insertCategoryValueCascadingGroup( - @RequestAttribute("company_code") String companyCode, - @RequestBody Map body) { - body.put("company_code", companyCode); - return ResponseEntity.ok(ApiResponse.success(categoryValueCascadingService.insertCategoryValueCascadingGroup(body))); - } - - /** PUT /groups/{groupId} → 그룹 수정 */ - @PutMapping("/groups/{groupId}") - public ResponseEntity>> updateCategoryValueCascadingGroup( - @RequestAttribute("company_code") String companyCode, - @PathVariable Long groupId, - @RequestBody Map body) { - body.put("company_code", companyCode); - body.put("group_id", groupId); - return ResponseEntity.ok(ApiResponse.success(categoryValueCascadingService.updateCategoryValueCascadingGroup(body))); - } - - /** DELETE /groups/{groupId} → 그룹 소프트 삭제 */ - @DeleteMapping("/groups/{groupId}") - public ResponseEntity>> deleteCategoryValueCascadingGroup( - @RequestAttribute("company_code") String companyCode, - @PathVariable Long groupId) { - Map params = new HashMap<>(); - params.put("company_code", companyCode); - params.put("group_id", groupId); - return ResponseEntity.ok(ApiResponse.success(categoryValueCascadingService.deleteCategoryValueCascadingGroup(params))); - } - - /** POST /groups/{groupId}/mappings → 매핑 일괄 저장 */ - @PostMapping("/groups/{groupId}/mappings") - public ResponseEntity>> saveCategoryValueCascadingMappings( - @RequestAttribute("company_code") String companyCode, - @PathVariable Long groupId, - @RequestBody Map body) { - body.put("company_code", companyCode); - body.put("group_id", groupId); - return ResponseEntity.ok(ApiResponse.success(categoryValueCascadingService.saveCategoryValueCascadingMappings(body))); - } - - /** GET /parent-options/{code} → 부모 카테고리 값 목록 */ - @GetMapping("/parent-options/{code}") - public ResponseEntity>> getCategoryValueCascadingParentOptions( - @RequestAttribute("company_code") String companyCode, - @PathVariable String code, - @RequestParam Map params) { - params.put("company_code", companyCode); - params.put("code", code); - return ResponseEntity.ok(ApiResponse.success(categoryValueCascadingService.getCategoryValueCascadingParentOptions(params))); - } - - /** GET /child-options/{code} → 자식 카테고리 값 목록 */ - @GetMapping("/child-options/{code}") - public ResponseEntity>> getCategoryValueCascadingChildOptions( - @RequestAttribute("company_code") String companyCode, - @PathVariable String code, - @RequestParam Map params) { - params.put("company_code", companyCode); - params.put("code", code); - return ResponseEntity.ok(ApiResponse.success(categoryValueCascadingService.getCategoryValueCascadingChildOptions(params))); - } - - /** GET /options/{code} → 연쇄 옵션 조회 (parentValue/parentValues 파라미터) */ - @GetMapping("/options/{code}") - public ResponseEntity>> getCategoryValueCascadingOptions( - @RequestAttribute("company_code") String companyCode, - @PathVariable String code, - @RequestParam Map params) { - params.put("company_code", companyCode); - params.put("code", code); - return ResponseEntity.ok(ApiResponse.success(categoryValueCascadingService.getCategoryValueCascadingOptions(params))); - } - - /** GET /table/{tableName}/mappings → 테이블별 매핑 조회 */ - @GetMapping("/table/{tableName}/mappings") - public ResponseEntity>> getCategoryValueCascadingMappingsByTable( - @RequestAttribute("company_code") String companyCode, - @PathVariable String tableName) { - Map params = new HashMap<>(); - params.put("company_code", companyCode); - params.put("table_name", tableName); - return ResponseEntity.ok(ApiResponse.success(categoryValueCascadingService.getCategoryValueCascadingMappingsByTable(params))); - } -} diff --git a/backend-spring/src/main/java/com/erp/controller/CodeMergeController.java b/backend-spring/src/main/java/com/erp/controller/CodeMergeController.java deleted file mode 100644 index 4874ad79..00000000 --- a/backend-spring/src/main/java/com/erp/controller/CodeMergeController.java +++ /dev/null @@ -1,69 +0,0 @@ -package com.erp.controller; - -import com.erp.dto.ApiResponse; -import com.erp.service.CodeMergeService; -import lombok.RequiredArgsConstructor; -import lombok.extern.slf4j.Slf4j; -import org.springframework.http.ResponseEntity; -import org.springframework.web.bind.annotation.*; - -import java.util.*; - -@RestController -@RequestMapping("/api/code-merge") -@RequiredArgsConstructor -@Slf4j -public class CodeMergeController { - - private final CodeMergeService codeMergeService; - - /** POST /api/code-merge/merge-all-tables — columnName 기준 전체 테이블 코드 병합 */ - @PostMapping("/merge-all-tables") - public ResponseEntity>> mergeAllTables( - @RequestAttribute("company_code") String companyCode, - @RequestBody Map body) { - body.put("company_code", companyCode); - return ResponseEntity.ok(ApiResponse.success( - codeMergeService.mergeAllTables(body), - "코드 병합이 완료되었습니다.")); - } - - /** GET /api/code-merge/tables-with-column/:columnName — 해당 컬럼을 가진 테이블 목록 */ - @GetMapping("/tables-with-column/{columnName}") - public ResponseEntity>> getTablesWithColumn( - @PathVariable String columnName) { - return ResponseEntity.ok(ApiResponse.success( - codeMergeService.getTablesWithColumn(columnName))); - } - - /** POST /api/code-merge/preview — columnName + oldValue 기준 영향 미리보기 */ - @PostMapping("/preview") - public ResponseEntity>> previewCodeMerge( - @RequestAttribute("company_code") String companyCode, - @RequestBody Map body) { - body.put("company_code", companyCode); - return ResponseEntity.ok(ApiResponse.success( - codeMergeService.previewCodeMerge(body))); - } - - /** POST /api/code-merge/merge-by-value — 값 기반 전체 테이블/컬럼 코드 병합 */ - @PostMapping("/merge-by-value") - public ResponseEntity>> mergeByValue( - @RequestAttribute("company_code") String companyCode, - @RequestBody Map body) { - body.put("company_code", companyCode); - return ResponseEntity.ok(ApiResponse.success( - codeMergeService.mergeByValue(body), - "코드 병합이 완료되었습니다.")); - } - - /** POST /api/code-merge/preview-by-value — 값 기반 영향 미리보기 */ - @PostMapping("/preview-by-value") - public ResponseEntity>> previewByValue( - @RequestAttribute("company_code") String companyCode, - @RequestBody Map body) { - body.put("company_code", companyCode); - return ResponseEntity.ok(ApiResponse.success( - codeMergeService.previewByValue(body))); - } -} diff --git a/backend-spring/src/main/java/com/erp/controller/CommonCodeController.java b/backend-spring/src/main/java/com/erp/controller/CommonCodeController.java index 2e9f4352..5f793a41 100644 --- a/backend-spring/src/main/java/com/erp/controller/CommonCodeController.java +++ b/backend-spring/src/main/java/com/erp/controller/CommonCodeController.java @@ -7,17 +7,18 @@ import lombok.extern.slf4j.Slf4j; import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.*; +import java.util.LinkedHashMap; import java.util.List; import java.util.Map; /** - * Common Code Controller + * Common Code Controller — 마스터-디테일 패턴. * - * commonCodeRoutes.ts 포팅 — /api/common-codes 기준 15개 엔드포인트. + * /info : code_info (1레벨 그룹 마스터) + * /detail : code_detail (2레벨~ 트리) * * NOTE: Spring MVC 는 리터럴 세그먼트를 경로변수보다 우선하므로 - * /check-duplicate, /reorder 는 별도 선언 순서 없이도 정상 동작하나, - * 가독성을 위해 구체적인 경로를 먼저 선언한다. + * /check-duplicate 는 /{codeInfo} / /{id} 보다 먼저 매칭된다. */ @RestController @RequestMapping("/api/common-codes") @@ -27,151 +28,200 @@ public class CommonCodeController { private final CommonCodeService service; - // ───────────────────────────────────────────────────────────── - // GET /categories - // Node.js: { success, data: [...], total, message } (flat, not nested) - // ───────────────────────────────────────────────────────────── + // ════════════════════════════════════════════════════════════════ + // CODE_INFO — 그룹 마스터 + // ════════════════════════════════════════════════════════════════ - @GetMapping("/categories") - public ResponseEntity> getCommonCodeCategoryList( + /** 그룹 목록 (페이징/검색) */ + @GetMapping("/info") + public ResponseEntity> getCodeInfoList( @RequestAttribute("company_code") String companyCode, @RequestParam Map params) { params.put("company_code", companyCode); - Map svcResult = service.getCommonCodeCategoryList(params); + Map svc = service.getCodeInfoList(params); - Map response = new java.util.LinkedHashMap<>(); + Map response = new LinkedHashMap<>(); response.put("success", true); - response.put("data", svcResult.get("data")); - response.put("total", svcResult.get("total")); - response.put("message", "카테고리 목록 조회 성공"); + response.put("data", svc.get("data")); + response.put("total", svc.get("total")); + response.put("message", "코드 그룹 목록 조회 성공"); return ResponseEntity.ok(response); } - // ───────────────────────────────────────────────────────────── - // GET /categories/check-duplicate ← /{categoryCode} 보다 먼저 - // ───────────────────────────────────────────────────────────── - - @GetMapping("/categories/check-duplicate") - public ResponseEntity>> checkCategoryDuplicate( + /** 그룹 중복 체크 — /{codeInfo} 보다 먼저 선언 */ + @GetMapping("/info/check-duplicate") + public ResponseEntity>> checkCodeInfoDuplicate( @RequestAttribute("company_code") String companyCode, - @RequestParam(defaultValue = "category_code") String field, + @RequestParam(defaultValue = "code_info") String field, @RequestParam String value, @RequestParam(required = false) String excludeCode) { return ResponseEntity.ok( - ApiResponse.success(service.checkCategoryDuplicate(field, value, excludeCode, companyCode))); + ApiResponse.success(service.checkCodeInfoDuplicate(field, value, excludeCode, companyCode))); } - // ───────────────────────────────────────────────────────────── - // POST /categories - // ───────────────────────────────────────────────────────────── + /** 그룹 단건 */ + @GetMapping("/info/{codeInfo}") + public ResponseEntity>> getCodeInfoInfo( + @RequestAttribute("company_code") String companyCode, + @PathVariable String codeInfo) { - @PostMapping("/categories") - public ResponseEntity>> insertCommonCodeCategory( + Map info = service.getCodeInfoInfo(codeInfo, companyCode); + if (info == null) { + return ResponseEntity.status(404).body(ApiResponse.error("코드 그룹을 찾을 수 없습니다.")); + } + return ResponseEntity.ok(ApiResponse.success(info)); + } + + /** 그룹 생성 */ + @PostMapping("/info") + public ResponseEntity>> insertCodeInfo( @RequestAttribute("company_code") String companyCode, @RequestAttribute("user_id") String userId, @RequestBody Map body) { - if (body.get("category_code") == null || body.get("category_name") == null) { + if (body.get("code_info") == null || body.get("code_name") == null) { return ResponseEntity.status(400) - .body(ApiResponse.error("필수 필드가 누락되었습니다. (categoryCode, categoryName)")); + .body(ApiResponse.error("필수 필드가 누락되었습니다. (code_info, code_name)")); } try { - Map created = service.insertCommonCodeCategory(body, companyCode, userId); + Map created = service.insertCodeInfo(body, companyCode, userId); return ResponseEntity.status(201) - .body(ApiResponse.success(created, "카테고리가 성공적으로 생성되었습니다.")); + .body(ApiResponse.success(created, "코드 그룹이 성공적으로 생성되었습니다.")); } catch (Exception e) { - log.error("카테고리 생성 실패", e); + log.error("코드 그룹 생성 실패", e); return ResponseEntity.status(500) - .body(ApiResponse.error("카테고리 생성에 실패했습니다.")); + .body(ApiResponse.error("코드 그룹 생성에 실패했습니다.")); } } - // ───────────────────────────────────────────────────────────── - // PUT /categories/:categoryCode - // ───────────────────────────────────────────────────────────── - - @PutMapping("/categories/{categoryCode}") - public ResponseEntity>> updateCommonCodeCategory( + /** 그룹 수정 */ + @PutMapping("/info/{codeInfo}") + public ResponseEntity>> updateCodeInfo( @RequestAttribute("company_code") String companyCode, @RequestAttribute("user_id") String userId, - @PathVariable String categoryCode, + @PathVariable String codeInfo, @RequestBody Map body) { try { - Map updated = service.updateCommonCodeCategory(categoryCode, body, companyCode, userId); + Map updated = service.updateCodeInfo(codeInfo, body, companyCode, userId); if (updated == null) { return ResponseEntity.status(404) - .body(ApiResponse.error("카테고리를 찾을 수 없습니다.")); + .body(ApiResponse.error("코드 그룹을 찾을 수 없습니다.")); } - return ResponseEntity.ok(ApiResponse.success(updated, "카테고리가 성공적으로 수정되었습니다.")); + return ResponseEntity.ok(ApiResponse.success(updated, "코드 그룹이 성공적으로 수정되었습니다.")); } catch (Exception e) { - log.error("카테고리 수정 실패", e); + log.error("코드 그룹 수정 실패", e); return ResponseEntity.status(500) - .body(ApiResponse.error("카테고리 수정에 실패했습니다.")); + .body(ApiResponse.error("코드 그룹 수정에 실패했습니다.")); } } - // ───────────────────────────────────────────────────────────── - // DELETE /categories/:categoryCode - // ───────────────────────────────────────────────────────────── - - @DeleteMapping("/categories/{categoryCode}") - public ResponseEntity> deleteCommonCodeCategory( + /** 그룹 삭제 (CASCADE 로 code_detail 자식 자동 삭제) */ + @DeleteMapping("/info/{codeInfo}") + public ResponseEntity> deleteCodeInfo( @RequestAttribute("company_code") String companyCode, - @PathVariable String categoryCode) { + @PathVariable String codeInfo) { try { - service.deleteCommonCodeCategory(categoryCode, companyCode); - return ResponseEntity.ok(ApiResponse.success(null, "카테고리가 성공적으로 삭제되었습니다.")); + service.deleteCodeInfo(codeInfo, companyCode); + return ResponseEntity.ok(ApiResponse.success(null, "코드 그룹이 성공적으로 삭제되었습니다.")); } catch (IllegalArgumentException e) { return ResponseEntity.status(404).body(ApiResponse.error(e.getMessage())); } catch (Exception e) { - log.error("카테고리 삭제 실패", e); + log.error("코드 그룹 삭제 실패", e); return ResponseEntity.status(500) - .body(ApiResponse.error("카테고리 삭제에 실패했습니다.")); + .body(ApiResponse.error("코드 그룹 삭제에 실패했습니다.")); } } - // ───────────────────────────────────────────────────────────── - // GET /categories/:categoryCode/codes - // ───────────────────────────────────────────────────────────── + // ════════════════════════════════════════════════════════════════ + // CODE_DETAIL — 디테일 트리 + // ════════════════════════════════════════════════════════════════ - @GetMapping("/categories/{categoryCode}/codes") - public ResponseEntity> getCommonCodeList( + /** + * 디테일 트리. + * - code_info 필수 (어느 그룹) + * - parent_detail_id (optional): 지정 시 해당 부모의 자식만, 미지정 시 그룹 전체 트리 (재귀 CTE) + * - flat=true 인 경우 동일 (트리는 평탄화된 depth+sort_order 순) + */ + @GetMapping("/detail") + public ResponseEntity> getCodeDetail( @RequestAttribute("company_code") String companyCode, - @PathVariable String categoryCode, + @RequestParam("code_info") String codeInfo, @RequestParam Map params) { params.put("company_code", companyCode); - Map svcResult = service.getCommonCodeList(categoryCode, params); - Map response = new java.util.LinkedHashMap<>(); + Object parentRaw = params.get("parent_detail_id"); + Map response = new LinkedHashMap<>(); response.put("success", true); - response.put("data", svcResult.get("data")); - response.put("total", svcResult.get("total")); - response.put("message", "코드 목록 조회 성공"); + + if (parentRaw != null && !parentRaw.toString().isEmpty()) { + // 특정 부모 직속 자식만 + Map svc = service.getCodeDetailList(codeInfo, params); + response.put("data", svc.get("data")); + response.put("total", svc.get("total")); + } else { + // 그룹 전체 트리 (재귀 CTE 로 평탄화) + List> tree = service.getCodeDetailTree(codeInfo, companyCode); + response.put("data", tree); + response.put("total", tree.size()); + } + response.put("message", "코드 디테일 조회 성공"); return ResponseEntity.ok(response); } - // ───────────────────────────────────────────────────────────── - // POST /categories/:categoryCode/codes - // ───────────────────────────────────────────────────────────── + /** 디테일 중복 체크 — /{id} 보다 먼저 선언 */ + @GetMapping("/detail/check-duplicate") + public ResponseEntity>> checkCodeDetailDuplicate( + @RequestAttribute("company_code") String companyCode, + @RequestParam("code_info") String codeInfo, + @RequestParam("code_value") String codeValue, + @RequestParam(value = "exclude_id", required = false) Long excludeId) { - @PostMapping("/categories/{categoryCode}/codes") - public ResponseEntity>> insertCommonCode( + return ResponseEntity.ok( + ApiResponse.success(service.checkCodeDetailDuplicate(codeInfo, codeValue, excludeId, companyCode))); + } + + /** 디테일 단건 */ + @GetMapping("/detail/{id}") + public ResponseEntity>> getCodeDetailInfo( + @RequestAttribute("company_code") String companyCode, + @PathVariable("id") Long codeDetailId) { + + Map info = service.getCodeDetailInfo(codeDetailId, companyCode); + if (info == null) { + return ResponseEntity.status(404).body(ApiResponse.error("코드를 찾을 수 없습니다.")); + } + return ResponseEntity.ok(ApiResponse.success(info)); + } + + /** 디테일 자식 존재 여부 */ + @GetMapping("/detail/{id}/has-children") + public ResponseEntity>> hasCodeDetailChildren( + @RequestAttribute("company_code") String companyCode, + @PathVariable("id") Long codeDetailId) { + + return ResponseEntity.ok( + ApiResponse.success(service.hasCodeDetailChildren(codeDetailId, companyCode))); + } + + /** 디테일 생성 */ + @PostMapping("/detail") + public ResponseEntity>> insertCodeDetail( @RequestAttribute("company_code") String companyCode, @RequestAttribute("user_id") String userId, - @PathVariable String categoryCode, @RequestBody Map body) { - if (body.get("code_value") == null || body.get("code_name") == null) { + Object codeInfoRaw = body.get("code_info"); + if (codeInfoRaw == null || body.get("code_value") == null || body.get("code_name") == null) { return ResponseEntity.status(400) - .body(ApiResponse.error("필수 필드가 누락되었습니다. (codeValue, codeName)")); + .body(ApiResponse.error("필수 필드가 누락되었습니다. (code_info, code_value, code_name)")); } try { - Map created = service.insertCommonCode(categoryCode, body, companyCode, userId); + Map created = service.insertCodeDetail(codeInfoRaw.toString(), body, companyCode, userId); return ResponseEntity.status(201) .body(ApiResponse.success(created, "코드가 성공적으로 생성되었습니다.")); } catch (Exception e) { @@ -181,122 +231,18 @@ public class CommonCodeController { } } - // ───────────────────────────────────────────────────────────── - // GET /categories/:categoryCode/codes/check-duplicate ← /{codeValue} 보다 먼저 - // ───────────────────────────────────────────────────────────── - - @GetMapping("/categories/{categoryCode}/codes/check-duplicate") - public ResponseEntity>> checkCodeDuplicate( - @RequestAttribute("company_code") String companyCode, - @PathVariable String categoryCode, - @RequestParam(defaultValue = "code_value") String field, - @RequestParam String value, - @RequestParam(required = false) String excludeCode) { - - return ResponseEntity.ok( - ApiResponse.success(service.checkCodeDuplicate(categoryCode, field, value, excludeCode, companyCode))); - } - - // ───────────────────────────────────────────────────────────── - // PUT /categories/:categoryCode/codes/reorder ← /{codeValue} 보다 먼저 - // ───────────────────────────────────────────────────────────── - - @SuppressWarnings("unchecked") - @PutMapping("/categories/{categoryCode}/codes/reorder") - public ResponseEntity> updateCommonCodeOrder( - @RequestAttribute("company_code") String companyCode, - @PathVariable String categoryCode, - @RequestBody Map body) { - - Object codesRaw = body.get("codes"); - if (!(codesRaw instanceof List)) { - return ResponseEntity.status(400) - .body(ApiResponse.error("codes 배열이 필요합니다.")); - } - try { - service.updateCommonCodeOrder(categoryCode, (List>) codesRaw, companyCode); - return ResponseEntity.ok(ApiResponse.success(null, "정렬 순서가 변경되었습니다.")); - } catch (Exception e) { - log.error("코드 정렬 변경 실패", e); - return ResponseEntity.status(500) - .body(ApiResponse.error("정렬 순서 변경에 실패했습니다.")); - } - } - - // ───────────────────────────────────────────────────────────── - // GET /categories/:categoryCode/hierarchy - // ───────────────────────────────────────────────────────────── - - @GetMapping("/categories/{categoryCode}/hierarchy") - public ResponseEntity>>> getCommonCodeHierarchicalList( - @RequestAttribute("company_code") String companyCode, - @PathVariable String categoryCode, - @RequestParam Map params) { - - params.put("company_code", companyCode); - return ResponseEntity.ok( - ApiResponse.success(service.getCommonCodeHierarchicalList(categoryCode, params))); - } - - // ───────────────────────────────────────────────────────────── - // GET /categories/:categoryCode/tree - // ───────────────────────────────────────────────────────────── - - @GetMapping("/categories/{categoryCode}/tree") - public ResponseEntity>> getCommonCodeTree( - @RequestAttribute("company_code") String companyCode, - @PathVariable String categoryCode) { - - return ResponseEntity.ok( - ApiResponse.success(service.getCommonCodeTree(categoryCode, companyCode))); - } - - // ───────────────────────────────────────────────────────────── - // GET /categories/:categoryCode/options - // ───────────────────────────────────────────────────────────── - - @GetMapping("/categories/{categoryCode}/options") - public ResponseEntity>>> getCommonCodeOptionList( - @RequestAttribute("company_code") String companyCode, - @PathVariable String categoryCode, - @RequestParam Map params) { - - params.put("company_code", companyCode); - return ResponseEntity.ok( - ApiResponse.success(service.getCommonCodeOptionList(categoryCode, params))); - } - - // ───────────────────────────────────────────────────────────── - // GET /categories/:categoryCode/codes/:codeValue/has-children - // ───────────────────────────────────────────────────────────── - - @GetMapping("/categories/{categoryCode}/codes/{codeValue}/has-children") - public ResponseEntity>> hasChildren( - @RequestAttribute("company_code") String companyCode, - @PathVariable String categoryCode, - @PathVariable String codeValue) { - - return ResponseEntity.ok( - ApiResponse.success(service.hasChildren(categoryCode, codeValue, companyCode))); - } - - // ───────────────────────────────────────────────────────────── - // PUT /categories/:categoryCode/codes/:codeValue - // ───────────────────────────────────────────────────────────── - - @PutMapping("/categories/{categoryCode}/codes/{codeValue}") - public ResponseEntity>> updateCommonCode( + /** 디테일 수정 */ + @PutMapping("/detail/{id}") + public ResponseEntity>> updateCodeDetail( @RequestAttribute("company_code") String companyCode, @RequestAttribute("user_id") String userId, - @PathVariable String categoryCode, - @PathVariable String codeValue, + @PathVariable("id") Long codeDetailId, @RequestBody Map body) { try { - Map updated = service.updateCommonCode(categoryCode, codeValue, body, companyCode, userId); + Map updated = service.updateCodeDetail(codeDetailId, body, companyCode, userId); if (updated == null) { - return ResponseEntity.status(404) - .body(ApiResponse.error("코드를 찾을 수 없습니다.")); + return ResponseEntity.status(404).body(ApiResponse.error("코드를 찾을 수 없습니다.")); } return ResponseEntity.ok(ApiResponse.success(updated, "코드가 성공적으로 수정되었습니다.")); } catch (Exception e) { @@ -306,18 +252,14 @@ public class CommonCodeController { } } - // ───────────────────────────────────────────────────────────── - // DELETE /categories/:categoryCode/codes/:codeValue - // ───────────────────────────────────────────────────────────── - - @DeleteMapping("/categories/{categoryCode}/codes/{codeValue}") - public ResponseEntity> deleteCommonCode( + /** 디테일 삭제 (CASCADE 로 자식 자동 삭제) */ + @DeleteMapping("/detail/{id}") + public ResponseEntity> deleteCodeDetail( @RequestAttribute("company_code") String companyCode, - @PathVariable String categoryCode, - @PathVariable String codeValue) { + @PathVariable("id") Long codeDetailId) { try { - service.deleteCommonCode(categoryCode, codeValue, companyCode); + service.deleteCodeDetail(codeDetailId, companyCode); return ResponseEntity.ok(ApiResponse.success(null, "코드가 성공적으로 삭제되었습니다.")); } catch (IllegalArgumentException e) { return ResponseEntity.status(404).body(ApiResponse.error(e.getMessage())); diff --git a/backend-spring/src/main/java/com/erp/controller/EntityReferenceController.java b/backend-spring/src/main/java/com/erp/controller/EntityReferenceController.java index 587230e6..f100ebf5 100644 --- a/backend-spring/src/main/java/com/erp/controller/EntityReferenceController.java +++ b/backend-spring/src/main/java/com/erp/controller/EntityReferenceController.java @@ -19,21 +19,21 @@ public class EntityReferenceController { private final EntityReferenceService entityReferenceService; /** - * GET /api/entity-reference/code/:codeCategory + * GET /api/entity-reference/code/:codeInfo * 공통 코드 데이터 조회 * * NOTE: Spring MVC는 리터럴 경로 세그먼트("code")를 변수 경로({tableName})보다 우선하므로 - * /code/{codeCategory} 가 /{tableName}/{columnName} 보다 먼저 매핑됨. + * /code/{codeInfo} 가 /{tableName}/{columnName} 보다 먼저 매핑됨. */ - @GetMapping("/code/{codeCategory}") + @GetMapping("/code/{codeInfo}") public ResponseEntity>> getCodeData( - @PathVariable String codeCategory, + @PathVariable String codeInfo, @RequestParam(required = false, defaultValue = "100") Integer limit, @RequestParam(required = false) String search, @RequestAttribute("company_code") String companyCode) { Map params = new HashMap<>(); - params.put("code_category", codeCategory); + params.put("code_info", codeInfo); params.put("company_code", companyCode); params.put("limit", limit); if (search != null) params.put("search", search); @@ -41,7 +41,7 @@ public class EntityReferenceController { try { return ResponseEntity.ok(ApiResponse.success(entityReferenceService.getCodeData(params))); } catch (Exception e) { - log.error("공통 코드 데이터 조회 실패: codeCategory={}", codeCategory, e); + log.error("공통 코드 데이터 조회 실패: codeInfo={}", codeInfo, e); return ResponseEntity.status(500).body(ApiResponse.error("공통 코드 데이터 조회 중 오류가 발생했습니다.")); } } diff --git a/backend-spring/src/main/java/com/erp/controller/ScreenManagementController.java b/backend-spring/src/main/java/com/erp/controller/ScreenManagementController.java index 7bd84d46..1fd71327 100644 --- a/backend-spring/src/main/java/com/erp/controller/ScreenManagementController.java +++ b/backend-spring/src/main/java/com/erp/controller/ScreenManagementController.java @@ -593,10 +593,10 @@ public class ScreenManagementController { } @PostMapping("/copy-code-category") - public ResponseEntity>> copyCodeCategoryAndCodes( + public ResponseEntity>> copyCodeInfoAndCodes( @RequestBody Map body) { try { - int count = service.copyCodeCategoryAndCodes(body); + int count = service.copyCodeInfoAndCodes(body); return ResponseEntity.ok(ApiResponse.success(Map.of("count", count))); } catch (Exception e) { log.error("코드 카테고리 복제 실패", e); diff --git a/backend-spring/src/main/java/com/erp/controller/TableCategoryValueController.java b/backend-spring/src/main/java/com/erp/controller/TableCategoryValueController.java deleted file mode 100644 index ba47099b..00000000 --- a/backend-spring/src/main/java/com/erp/controller/TableCategoryValueController.java +++ /dev/null @@ -1,373 +0,0 @@ -package com.erp.controller; - -import com.erp.dto.ApiResponse; -import com.erp.service.TableCategoryValueService; -import lombok.RequiredArgsConstructor; -import lombok.extern.slf4j.Slf4j; -import org.springframework.http.HttpStatus; -import org.springframework.http.ResponseEntity; -import org.springframework.web.bind.annotation.*; - -import java.util.HashMap; -import java.util.List; -import java.util.Map; - -@RestController -@RequestMapping("/api/table-categories") -@RequiredArgsConstructor -@Slf4j -public class TableCategoryValueController { - - private final TableCategoryValueService service; - - // ══════════════════════════════════════════════════════════════ - // Category Columns - // ══════════════════════════════════════════════════════════════ - - /** GET /api/table-categories/all-columns */ - @GetMapping("/all-columns") - public ResponseEntity>>> getAllCategoryColumns( - @RequestAttribute("company_code") String companyCode) { - try { - Map params = new HashMap<>(); - params.put("company_code", companyCode); - return ResponseEntity.ok(ApiResponse.success(service.getAllCategoryColumns(params))); - } catch (Exception e) { - log.error("전체 카테고리 컬럼 조회 실패", e); - return ResponseEntity.status(500) - .body(ApiResponse.error("전체 카테고리 컬럼 조회 중 오류가 발생했습니다")); - } - } - - /** GET /api/table-categories/{tableName}/columns */ - @GetMapping("/{tableName}/columns") - public ResponseEntity>>> getCategoryColumns( - @PathVariable String tableName, - @RequestAttribute("company_code") String companyCode) { - try { - Map params = new HashMap<>(); - params.put("table_name", tableName); - params.put("company_code", companyCode); - return ResponseEntity.ok(ApiResponse.success(service.getCategoryColumns(params))); - } catch (Exception e) { - log.error("카테고리 컬럼 조회 실패: tableName={}", tableName, e); - return ResponseEntity.status(500) - .body(ApiResponse.error("카테고리 컬럼 조회 중 오류가 발생했습니다")); - } - } - - // ══════════════════════════════════════════════════════════════ - // Category Values — Read - // ══════════════════════════════════════════════════════════════ - - /** GET /api/table-categories/{tableName}/{columnName}/values */ - @GetMapping("/{tableName}/{columnName}/values") - public ResponseEntity>>> getCategoryValues( - @PathVariable String tableName, - @PathVariable String columnName, - @RequestParam(required = false) String menuObjid, - @RequestParam(required = false, defaultValue = "false") boolean includeInactive, - @RequestParam(required = false) String filterCompanyCode, - @RequestAttribute("company_code") String companyCode) { - try { - // SUPER_ADMIN 이 특정 회사 기준 필터링 요청 시 해당 companyCode 사용 - String effectiveCompanyCode = ("*".equals(companyCode) && filterCompanyCode != null) - ? filterCompanyCode : companyCode; - - Map params = new HashMap<>(); - params.put("table_name", tableName); - params.put("column_name", columnName); - params.put("company_code", effectiveCompanyCode); - params.put("include_inactive", includeInactive); - if (menuObjid != null) params.put("menu_objid", Long.parseLong(menuObjid)); - - return ResponseEntity.ok(ApiResponse.success(service.getCategoryValues(params))); - } catch (Exception e) { - log.error("카테고리 값 조회 실패: tableName={}, columnName={}", tableName, columnName, e); - return ResponseEntity.status(500) - .body(ApiResponse.error("카테고리 값 조회 중 오류가 발생했습니다")); - } - } - - // ══════════════════════════════════════════════════════════════ - // Category Values — Write - // ══════════════════════════════════════════════════════════════ - - /** POST /api/table-categories/values */ - @PostMapping("/values") - public ResponseEntity>> addCategoryValue( - @RequestBody Map body, - @RequestAttribute("company_code") String companyCode, - @RequestAttribute("user_id") String userId) { - if (body.get("menu_objid") == null) { - return ResponseEntity.status(400).body(ApiResponse.error("menuObjid는 필수입니다")); - } - body.put("company_code", companyCode); - body.put("user_id", userId); - try { - return ResponseEntity.status(HttpStatus.CREATED) - .body(ApiResponse.success(service.addCategoryValue(body))); - } catch (IllegalArgumentException e) { - return ResponseEntity.status(500).body(ApiResponse.error( - e.getMessage() != null ? e.getMessage() : "카테고리 값 추가 중 오류가 발생했습니다")); - } catch (Exception e) { - log.error("카테고리 값 추가 실패", e); - return ResponseEntity.status(500).body(ApiResponse.error("카테고리 값 추가 중 오류가 발생했습니다")); - } - } - - /** PUT /api/table-categories/values/{valueId} */ - @PutMapping("/values/{valueId}") - public ResponseEntity>> updateCategoryValue( - @PathVariable Long valueId, - @RequestBody Map body, - @RequestAttribute("company_code") String companyCode, - @RequestAttribute("user_id") String userId) { - body.put("value_id", valueId); - body.put("company_code", companyCode); - body.put("user_id", userId); - try { - return ResponseEntity.ok(ApiResponse.success(service.updateCategoryValue(body))); - } catch (IllegalArgumentException e) { - return ResponseEntity.status(500).body(ApiResponse.error("카테고리 값 수정 중 오류가 발생했습니다")); - } catch (Exception e) { - log.error("카테고리 값 수정 실패: valueId={}", valueId, e); - return ResponseEntity.status(500).body(ApiResponse.error("카테고리 값 수정 중 오류가 발생했습니다")); - } - } - - /** DELETE /api/table-categories/values/{valueId} */ - @DeleteMapping("/values/{valueId}") - public ResponseEntity> deleteCategoryValue( - @PathVariable Long valueId, - @RequestAttribute("company_code") String companyCode, - @RequestAttribute("user_id") String userId) { - Map params = new HashMap<>(); - params.put("value_id", valueId); - params.put("company_code", companyCode); - params.put("user_id", userId); - try { - service.deleteCategoryValue(params); - return ResponseEntity.ok(ApiResponse.success(null, "카테고리 값이 삭제되었습니다")); - } catch (IllegalArgumentException e) { - // 사용 중인 경우 400 - if (e.getMessage() != null && e.getMessage().contains("삭제할 수 없습니다")) { - return ResponseEntity.status(400).body(ApiResponse.error(e.getMessage())); - } - return ResponseEntity.status(500).body(ApiResponse.error( - e.getMessage() != null ? e.getMessage() : "카테고리 값 삭제 중 오류가 발생했습니다")); - } catch (Exception e) { - log.error("카테고리 값 삭제 실패: valueId={}", valueId, e); - return ResponseEntity.status(500).body(ApiResponse.error("카테고리 값 삭제 중 오류가 발생했습니다")); - } - } - - /** POST /api/table-categories/values/bulk-delete */ - @PostMapping("/values/bulk-delete") - public ResponseEntity> bulkDeleteCategoryValues( - @RequestBody Map body, - @RequestAttribute("company_code") String companyCode, - @RequestAttribute("user_id") String userId) { - Object rawIds = body.get("value_ids"); - if (!(rawIds instanceof List) || ((List) rawIds).isEmpty()) { - return ResponseEntity.status(400).body(ApiResponse.error("삭제할 값 ID 목록이 필요합니다")); - } - body.put("company_code", companyCode); - body.put("user_id", userId); - try { - service.bulkDeleteCategoryValues(body); - int count = ((List) rawIds).size(); - return ResponseEntity.ok( - ApiResponse.success(null, count + "개의 카테고리 값이 삭제되었습니다")); - } catch (Exception e) { - log.error("카테고리 값 일괄 삭제 실패", e); - return ResponseEntity.status(500).body(ApiResponse.error("카테고리 값 일괄 삭제 중 오류가 발생했습니다")); - } - } - - /** POST /api/table-categories/values/reorder */ - @PostMapping("/values/reorder") - public ResponseEntity> reorderCategoryValues( - @RequestBody Map body, - @RequestAttribute("company_code") String companyCode) { - Object rawIds = body.get("ordered_value_ids"); - if (!(rawIds instanceof List) || ((List) rawIds).isEmpty()) { - return ResponseEntity.status(400).body(ApiResponse.error("순서 정보가 필요합니다")); - } - body.put("company_code", companyCode); - try { - service.reorderCategoryValues(body); - return ResponseEntity.ok(ApiResponse.success(null, "카테고리 값 순서가 변경되었습니다")); - } catch (Exception e) { - log.error("카테고리 값 순서 변경 실패", e); - return ResponseEntity.status(500).body(ApiResponse.error("카테고리 값 순서 변경 중 오류가 발생했습니다")); - } - } - - // ══════════════════════════════════════════════════════════════ - // Labels by Codes - // ══════════════════════════════════════════════════════════════ - - /** POST /api/table-categories/labels-by-codes */ - @PostMapping("/labels-by-codes") - public ResponseEntity>> getCategoryLabelsByCodes( - @RequestBody Map body, - @RequestAttribute("company_code") String companyCode) { - Object rawCodes = body.get("value_codes"); - if (!(rawCodes instanceof List) || ((List) rawCodes).isEmpty()) { - return ResponseEntity.ok(ApiResponse.success(new java.util.LinkedHashMap<>())); - } - body.put("company_code", companyCode); - try { - return ResponseEntity.ok(ApiResponse.success(service.getCategoryLabelsByCodes(body))); - } catch (Exception e) { - log.error("카테고리 라벨 조회 실패", e); - return ResponseEntity.status(500).body(ApiResponse.error("카테고리 라벨 조회 중 오류가 발생했습니다")); - } - } - - // ══════════════════════════════════════════════════════════════ - // Second-Level Menus (NOTE: 리터럴 경로이므로 variable 경로보다 우선) - // ══════════════════════════════════════════════════════════════ - - /** GET /api/table-categories/second-level-menus */ - @GetMapping("/second-level-menus") - public ResponseEntity>>> getSecondLevelMenus( - @RequestAttribute("company_code") String companyCode) { - try { - Map params = new HashMap<>(); - params.put("company_code", companyCode); - return ResponseEntity.ok(ApiResponse.success(service.getSecondLevelMenus(params))); - } catch (Exception e) { - log.error("2레벨 메뉴 목록 조회 실패", e); - return ResponseEntity.status(500).body(ApiResponse.error("2레벨 메뉴 목록 조회 중 오류가 발생했습니다")); - } - } - - // ══════════════════════════════════════════════════════════════ - // Column Mapping - // ══════════════════════════════════════════════════════════════ - - /** GET /api/table-categories/column-mapping/{tableName}/{menuObjid} */ - @GetMapping("/column-mapping/{tableName}/{menuObjid}") - public ResponseEntity>> getColumnMapping( - @PathVariable String tableName, - @PathVariable Long menuObjid, - @RequestAttribute("company_code") String companyCode) { - try { - Map params = new HashMap<>(); - params.put("table_name", tableName); - params.put("menu_objid", menuObjid); - params.put("company_code", companyCode); - return ResponseEntity.ok(ApiResponse.success(service.getColumnMapping(params))); - } catch (Exception e) { - log.error("컬럼 매핑 조회 실패: tableName={}, menuObjid={}", tableName, menuObjid, e); - return ResponseEntity.status(500).body(ApiResponse.error("컬럼 매핑 조회 중 오류가 발생했습니다")); - } - } - - /** GET /api/table-categories/logical-columns/{tableName}/{menuObjid} */ - @GetMapping("/logical-columns/{tableName}/{menuObjid}") - public ResponseEntity>>> getLogicalColumns( - @PathVariable String tableName, - @PathVariable Long menuObjid, - @RequestAttribute("company_code") String companyCode) { - try { - Map params = new HashMap<>(); - params.put("table_name", tableName); - params.put("menu_objid", menuObjid); - params.put("company_code", companyCode); - return ResponseEntity.ok(ApiResponse.success(service.getLogicalColumns(params))); - } catch (Exception e) { - log.error("논리적 컬럼 목록 조회 실패: tableName={}, menuObjid={}", tableName, menuObjid, e); - return ResponseEntity.status(500).body(ApiResponse.error("논리적 컬럼 목록 조회 중 오류가 발생했습니다")); - } - } - - /** POST /api/table-categories/column-mapping */ - @PostMapping("/column-mapping") - public ResponseEntity>> createColumnMapping( - @RequestBody Map body, - @RequestAttribute("company_code") String companyCode, - @RequestAttribute("user_id") String userId) { - String tableName = (String) body.get("table_name"); - String logicalColumnName = (String) body.get("logical_column_name"); - String physicalColumnName = (String) body.get("physical_column_name"); - Object menuObjid = body.get("menu_objid"); - - if (tableName == null || logicalColumnName == null - || physicalColumnName == null || menuObjid == null) { - return ResponseEntity.status(400).body(ApiResponse.error( - "tableName, logicalColumnName, physicalColumnName, menuObjid는 필수입니다")); - } - - body.put("company_code", companyCode); - body.put("user_id", userId); - // menuObjid를 Long으로 보장 - body.put("menu_objid", toLong(menuObjid)); - - try { - return ResponseEntity.status(HttpStatus.CREATED) - .body(ApiResponse.success(service.createColumnMapping(body), "컬럼 매핑이 생성되었습니다")); - } catch (IllegalArgumentException e) { - return ResponseEntity.status(500).body(ApiResponse.error( - e.getMessage() != null ? e.getMessage() : "컬럼 매핑 생성 중 오류가 발생했습니다")); - } catch (Exception e) { - log.error("컬럼 매핑 생성 실패", e); - return ResponseEntity.status(500).body(ApiResponse.error("컬럼 매핑 생성 중 오류가 발생했습니다")); - } - } - - /** - * DELETE /api/table-categories/column-mapping/{tableName}/{columnName}/all - * NOTE: 3-segment 경로이므로 /{mappingId} 1-segment 경로보다 Spring이 우선 매핑. - */ - @DeleteMapping("/column-mapping/{tableName}/{columnName}/all") - public ResponseEntity>> deleteColumnMappingsByColumn( - @PathVariable String tableName, - @PathVariable String columnName, - @RequestAttribute("company_code") String companyCode) { - try { - Map params = new HashMap<>(); - params.put("table_name", tableName); - params.put("column_name", columnName); - params.put("company_code", companyCode); - int deleted = service.deleteColumnMappingsByColumn(params); - Map data = new HashMap<>(); - data.put("deleted_count", deleted); - return ResponseEntity.ok(ApiResponse.success(data, - deleted + "개의 컬럼 매핑이 삭제되었습니다")); - } catch (Exception e) { - log.error("테이블+컬럼 기준 매핑 삭제 실패: tableName={}, columnName={}", tableName, columnName, e); - return ResponseEntity.status(500).body(ApiResponse.error("컬럼 매핑 삭제 중 오류가 발생했습니다")); - } - } - - /** DELETE /api/table-categories/column-mapping/{mappingId} */ - @DeleteMapping("/column-mapping/{mappingId}") - public ResponseEntity> deleteColumnMapping( - @PathVariable Long mappingId, - @RequestAttribute("company_code") String companyCode) { - Map params = new HashMap<>(); - params.put("mapping_id", mappingId); - params.put("company_code", companyCode); - try { - service.deleteColumnMapping(params); - return ResponseEntity.ok(ApiResponse.success(null, "컬럼 매핑이 삭제되었습니다")); - } catch (IllegalArgumentException e) { - return ResponseEntity.status(500).body(ApiResponse.error( - e.getMessage() != null ? e.getMessage() : "컬럼 매핑 삭제 중 오류가 발생했습니다")); - } catch (Exception e) { - log.error("컬럼 매핑 삭제 실패: mappingId={}", mappingId, e); - return ResponseEntity.status(500).body(ApiResponse.error("컬럼 매핑 삭제 중 오류가 발생했습니다")); - } - } - - // ── private util ─────────────────────────────────────────────── - - private long toLong(Object val) { - if (val == null) return 0L; - if (val instanceof Number) return ((Number) val).longValue(); - try { return Long.parseLong(val.toString()); } catch (NumberFormatException e) { return 0L; } - } -} diff --git a/backend-spring/src/main/java/com/erp/service/CascadingAutoFillService.java b/backend-spring/src/main/java/com/erp/service/CascadingAutoFillService.java deleted file mode 100644 index 935c86a0..00000000 --- a/backend-spring/src/main/java/com/erp/service/CascadingAutoFillService.java +++ /dev/null @@ -1,270 +0,0 @@ -package com.erp.service; - -import com.erp.common.BaseService; -import lombok.extern.slf4j.Slf4j; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.jdbc.core.JdbcTemplate; -import org.springframework.stereotype.Service; -import org.springframework.transaction.annotation.Transactional; -import java.util.*; -import java.util.stream.Collectors; - -@Service -@Slf4j -public class CascadingAutoFillService extends BaseService { - - private static final String NS = "cascadingAutoFill."; - - @Autowired - private CommonService commonService; - @Autowired - private JdbcTemplate jdbcTemplate; - - public Map getCascadingAutoFillGroupList(Map params) { - commonService.applyCompanyCodeFilter(params); - commonService.applyPagination(params); - int totalCount = sqlSession.selectOne(NS + "getCascadingAutoFillGroupListCnt", params); - List> list = sqlSession.selectList(NS + "getCascadingAutoFillGroupList", params); - return commonService.buildListResponse(list, totalCount, params); - } - - public Map getCascadingAutoFillGroupDetail(Map params) { - commonService.applyCompanyCodeFilter(params); - Map group = sqlSession.selectOne(NS + "getCascadingAutoFillGroupByCode", params); - if (group == null) return null; - - Map mappingParams = new HashMap<>(); - mappingParams.put("group_code", params.get("group_code")); - mappingParams.put("company_code", group.get("company_code")); - List> mappings = sqlSession.selectList(NS + "getCascadingAutoFillMappingList", mappingParams); - - Map result = new HashMap<>(group); - result.put("mappings", mappings); - return result; - } - - @Transactional - public Map insertCascadingAutoFillGroup(Map params) { - commonService.applyCompanyCodeFilter(params); - String companyCode = (String) params.get("company_code"); - - // Generate group code: AF_{timestamp_base36}_{count:03d} - Map countParams = new HashMap<>(); - countParams.put("company_code", companyCode); - Number cntNum = sqlSession.selectOne(NS + "getCascadingAutoFillGroupCount", countParams); - int count = (cntNum != null ? cntNum.intValue() : 0) + 1; - String timestamp = Long.toString(System.currentTimeMillis(), 36).toUpperCase(); - String suffix = timestamp.substring(Math.max(0, timestamp.length() - 4)); - String groupCode = "AF_" + suffix + "_" + String.format("%03d", count); - params.put("group_code", groupCode); - - if (params.get("is_active") == null) { - params.put("is_active", "Y"); - } - - sqlSession.insert(NS + "insertCascadingAutoFillGroup", params); - - // Insert mappings - Object mappingsObj = params.get("mappings"); - if (mappingsObj instanceof List) { - List mappings = (List) mappingsObj; - for (int i = 0; i < mappings.size(); i++) { - Object m = mappings.get(i); - if (m instanceof Map) { - @SuppressWarnings("unchecked") - Map mapping = (Map) m; - Map mp = new HashMap<>(mapping); - mp.put("group_code", groupCode); - mp.put("company_code", companyCode); - if (mp.get("is_editable") == null) mp.put("is_editable", "Y"); - if (mp.get("is_required") == null) mp.put("is_required", "N"); - if (mp.get("sort_order") == null) mp.put("sort_order", i + 1); - sqlSession.insert(NS + "insertCascadingAutoFillMapping", mp); - } - } - } - return params; - } - - @Transactional - public Map updateCascadingAutoFillGroup(Map params) { - commonService.applyCompanyCodeFilter(params); - String groupCode = (String) params.get("group_code"); - - Map existing = sqlSession.selectOne(NS + "getCascadingAutoFillGroupByCode", params); - if (existing == null) return null; - - String actualCompanyCode = (String) existing.get("company_code"); - params.put("company_code", actualCompanyCode); - - sqlSession.update(NS + "updateCascadingAutoFillGroup", params); - - // Replace mappings if provided - if (params.containsKey("mappings")) { - Map delParams = new HashMap<>(); - delParams.put("group_code", groupCode); - delParams.put("company_code", actualCompanyCode); - sqlSession.delete(NS + "deleteCascadingAutoFillMappings", delParams); - - Object mappingsObj = params.get("mappings"); - if (mappingsObj instanceof List) { - List mappings = (List) mappingsObj; - for (int i = 0; i < mappings.size(); i++) { - Object m = mappings.get(i); - if (m instanceof Map) { - @SuppressWarnings("unchecked") - Map mapping = (Map) m; - Map mp = new HashMap<>(mapping); - mp.put("group_code", groupCode); - mp.put("company_code", actualCompanyCode); - if (mp.get("is_editable") == null) mp.put("is_editable", "Y"); - if (mp.get("is_required") == null) mp.put("is_required", "N"); - if (mp.get("sort_order") == null) mp.put("sort_order", i + 1); - sqlSession.insert(NS + "insertCascadingAutoFillMapping", mp); - } - } - } - } - return params; - } - - @Transactional - public boolean deleteCascadingAutoFillGroup(Map params) { - commonService.applyCompanyCodeFilter(params); - Map existing = sqlSession.selectOne(NS + "getCascadingAutoFillGroupByCode", params); - if (existing == null) return false; - - String groupCode = (String) params.get("group_code"); - String companyCode = (String) existing.get("company_code"); - - Map delParams = new HashMap<>(); - delParams.put("group_code", groupCode); - delParams.put("company_code", companyCode); - sqlSession.delete(NS + "deleteCascadingAutoFillMappings", delParams); - sqlSession.delete(NS + "deleteCascadingAutoFillGroup", delParams); - return true; - } - - public List> getAutoFillMasterOptions(Map params) { - commonService.applyCompanyCodeFilter(params); - String companyCode = (String) params.get("company_code"); - - Map groupParams = new HashMap<>(params); - groupParams.put("is_active", "Y"); - Map group = sqlSession.selectOne(NS + "getCascadingAutoFillGroupByCode", groupParams); - if (group == null) return null; - - String masterTable = sanitizeIdentifier((String) group.get("master_table")); - String masterValueColumn = sanitizeIdentifier((String) group.get("master_value_column")); - Object labelColObj = group.get("master_label_column"); - String labelColumn = (labelColObj != null && !labelColObj.toString().isEmpty()) - ? sanitizeIdentifier(labelColObj.toString()) : masterValueColumn; - - StringBuilder sql = new StringBuilder(); - sql.append("SELECT ").append(masterValueColumn).append(" AS value, ") - .append(labelColumn).append(" AS label") - .append(" FROM ").append(masterTable) - .append(" WHERE 1=1"); - - List sqlParams = new ArrayList<>(); - - if (!"*".equals(companyCode) && hasColumn(masterTable, "company_code")) { - sql.append(" AND company_code = ?"); - sqlParams.add(companyCode); - } - sql.append(" ORDER BY ").append(labelColumn); - - return jdbcTemplate.queryForList(sql.toString(), sqlParams.toArray()); - } - - public Map getAutoFillData(Map params) { - commonService.applyCompanyCodeFilter(params); - String groupCode = (String) params.get("group_code"); - String masterValue = (String) params.get("master_value"); - String companyCode = (String) params.get("company_code"); - - Map groupParams = new HashMap<>(params); - groupParams.put("is_active", "Y"); - Map group = sqlSession.selectOne(NS + "getCascadingAutoFillGroupByCode", groupParams); - if (group == null) return null; - - String actualCompanyCode = (String) group.get("company_code"); - Map mappingParams = new HashMap<>(); - mappingParams.put("group_code", groupCode); - mappingParams.put("company_code", actualCompanyCode); - List> mappings = sqlSession.selectList(NS + "getCascadingAutoFillMappingList", mappingParams); - - if (mappings.isEmpty()) { - Map empty = new HashMap<>(); - empty.put("data", new HashMap<>()); - empty.put("mappings", new ArrayList<>()); - return empty; - } - - String masterTable = sanitizeIdentifier((String) group.get("master_table")); - String masterValueColumn = sanitizeIdentifier((String) group.get("master_value_column")); - String sourceColumns = mappings.stream() - .map(m -> sanitizeIdentifier((String) m.get("source_column"))) - .collect(Collectors.joining(", ")); - - StringBuilder sql = new StringBuilder(); - sql.append("SELECT ").append(sourceColumns) - .append(" FROM ").append(masterTable) - .append(" WHERE ").append(masterValueColumn).append(" = ?"); - - List sqlParams = new ArrayList<>(); - sqlParams.add(masterValue); - - if (!"*".equals(companyCode) && hasColumn(masterTable, "company_code")) { - sql.append(" AND company_code = ?"); - sqlParams.add(companyCode); - } - - List> rows = jdbcTemplate.queryForList(sql.toString(), sqlParams.toArray()); - Map dataRow = rows.isEmpty() ? null : rows.get(0); - - Map autoFillData = new LinkedHashMap<>(); - List> mappingInfo = new ArrayList<>(); - - for (Map mapping : mappings) { - String sourceColumn = (String) mapping.get("source_column"); - String targetField = (String) mapping.get("target_field"); - Object sourceValue = (dataRow != null) ? dataRow.get(sourceColumn) : null; - Object defaultVal = mapping.get("default_value"); - Object finalValue = (sourceValue != null) ? sourceValue : defaultVal; - - autoFillData.put(targetField, finalValue); - - Map info = new LinkedHashMap<>(); - info.put("target_field", targetField); - info.put("target_label", mapping.get("target_label")); - info.put("value", finalValue); - info.put("is_editable", "Y".equals(mapping.get("is_editable"))); - info.put("is_required", "Y".equals(mapping.get("is_required"))); - mappingInfo.add(info); - } - - Map result = new HashMap<>(); - result.put("data", autoFillData); - result.put("mappings", mappingInfo); - return result; - } - - private String sanitizeIdentifier(String identifier) { - if (identifier == null || !identifier.matches("[a-zA-Z0-9_.]+")) { - throw new IllegalArgumentException("Invalid SQL identifier: " + identifier); - } - return identifier; - } - - private boolean hasColumn(String tableName, String columnName) { - try { - Integer count = jdbcTemplate.queryForObject( - "SELECT COUNT(*) FROM information_schema.columns WHERE table_name = ? AND column_name = ?", - Integer.class, tableName, columnName); - return count != null && count > 0; - } catch (Exception e) { - return false; - } - } -} diff --git a/backend-spring/src/main/java/com/erp/service/CascadingConditionService.java b/backend-spring/src/main/java/com/erp/service/CascadingConditionService.java deleted file mode 100644 index 210a905f..00000000 --- a/backend-spring/src/main/java/com/erp/service/CascadingConditionService.java +++ /dev/null @@ -1,198 +0,0 @@ -package com.erp.service; - -import com.erp.common.BaseService; -import lombok.extern.slf4j.Slf4j; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.jdbc.core.JdbcTemplate; -import org.springframework.stereotype.Service; -import org.springframework.transaction.annotation.Transactional; -import java.util.*; -import java.util.stream.Collectors; - -@Service -@Slf4j -public class CascadingConditionService extends BaseService { - - private static final String NS = "cascadingCondition."; - private static final String NS_RELATION = "cascadingRelation."; - - @Autowired - private CommonService commonService; - @Autowired - private JdbcTemplate jdbcTemplate; - - public Map getCascadingConditionList(Map params) { - commonService.applyCompanyCodeFilter(params); - commonService.applyPagination(params); - int totalCount = sqlSession.selectOne(NS + "getCascadingConditionListCnt", params); - List> list = sqlSession.selectList(NS + "getCascadingConditionList", params); - return commonService.buildListResponse(list, totalCount, params); - } - - public Map getCascadingConditionInfo(Map params) { - commonService.applyCompanyCodeFilter(params); - return sqlSession.selectOne(NS + "getCascadingConditionInfo", params); - } - - @Transactional - public Map insertCascadingCondition(Map params) { - commonService.applyCompanyCodeFilter(params); - sqlSession.insert(NS + "insertCascadingCondition", params); - return params; - } - - @Transactional - public Map updateCascadingCondition(Map params) { - commonService.applyCompanyCodeFilter(params); - sqlSession.update(NS + "updateCascadingCondition", params); - return params; - } - - @Transactional - public Map deleteCascadingCondition(Map params) { - commonService.applyCompanyCodeFilter(params); - sqlSession.delete(NS + "deleteCascadingCondition", params); - return params; - } - - public Map getFilteredOptions(Map params) { - commonService.applyCompanyCodeFilter(params); - String companyCode = (String) params.get("company_code"); - String conditionFieldValue = params.get("condition_field_value") != null - ? String.valueOf(params.get("condition_field_value")) : null; - String parentValue = params.get("parent_value") != null - ? String.valueOf(params.get("parent_value")) : null; - - // 1. 연쇄 관계 조회 - Map relation = sqlSession.selectOne(NS_RELATION + "get_cascading_relation_by_code", params); - if (relation == null) { - Map empty = new LinkedHashMap<>(); - empty.put("data", Collections.emptyList()); - empty.put("applied_condition", null); - return empty; - } - - // 2. 조건 규칙 조회 (우선순위 내림차순) - List> conditions = sqlSession.selectList(NS + "getCascadingConditionsByRelationCode", params); - - // 3. 매칭 조건 탐색 - Map matchedCondition = null; - if (conditionFieldValue != null) { - for (Map cond : conditions) { - String operator = (String) cond.get("condition_operator"); - String expectedValue = (String) cond.get("condition_value"); - if (evaluateCondition(conditionFieldValue, operator, expectedValue)) { - matchedCondition = cond; - break; - } - } - } - - // 4. 동적 옵션 쿼리 생성 - String childTable = String.valueOf(relation.get("child_table")); - String valueCol = String.valueOf(relation.get("child_value_column")); - String labelCol = String.valueOf(relation.get("child_label_column")); - Object filterColObj = relation.get("child_filter_column"); - Object orderColObj = relation.get("child_order_column"); - String filterCol = filterColObj != null ? String.valueOf(filterColObj) : null; - String orderCol = orderColObj != null ? String.valueOf(orderColObj) : null; - String orderDir = relation.get("child_order_direction") != null - ? String.valueOf(relation.get("child_order_direction")) : "ASC"; - - StringBuilder sql = new StringBuilder("SELECT ") - .append(valueCol).append(" as value, ") - .append(labelCol).append(" as label FROM ") - .append(childTable).append(" WHERE 1=1"); - List sqlParams = new ArrayList<>(); - - if (parentValue != null && filterCol != null && !filterCol.isEmpty()) { - sql.append(" AND ").append(filterCol).append(" = ?"); - sqlParams.add(parentValue); - } - - if (matchedCondition != null) { - String condFilterColumn = (String) matchedCondition.get("filter_column"); - String condFilterValues = (String) matchedCondition.get("filter_values"); - if (condFilterColumn != null && condFilterValues != null) { - String[] values = condFilterValues.split(","); - String placeholders = Arrays.stream(values).map(v -> "?").collect(Collectors.joining(",")); - sql.append(" AND ").append(condFilterColumn).append(" IN (").append(placeholders).append(")"); - for (String v : values) sqlParams.add(v.trim()); - } - } - - // 멀티테넌시 필터 (child_table에 company_code 컬럼이 있는 경우만) - if (companyCode != null && !"*".equals(companyCode)) { - try { - Integer cnt = jdbcTemplate.queryForObject( - "SELECT COUNT(*) FROM information_schema.columns WHERE table_name = ? AND column_name = 'company_code'", - Integer.class, childTable); - if (cnt != null && cnt > 0) { - sql.append(" AND company_code = ?"); - sqlParams.add(companyCode); - } - } catch (Exception e) { - log.warn("company_code 컬럼 확인 실패: {}", e.getMessage()); - } - } - - sql.append(" ORDER BY "); - if (orderCol != null && !orderCol.isEmpty()) { - sql.append(orderCol).append(" ").append(orderDir); - } else { - sql.append(labelCol); - } - - List> options = jdbcTemplate.queryForList(sql.toString(), sqlParams.toArray()); - - Map result = new LinkedHashMap<>(); - result.put("data", options); - if (matchedCondition != null) { - Map applied = new HashMap<>(); - applied.put("condition_id", matchedCondition.get("condition_id")); - applied.put("condition_name", matchedCondition.get("condition_name")); - result.put("applied_condition", applied); - } else { - result.put("applied_condition", null); - } - return result; - } - - private boolean evaluateCondition(String actualValue, String operator, String expectedValue) { - if (operator == null || actualValue == null || expectedValue == null) return false; - String actual = actualValue.toLowerCase().trim(); - String expected = expectedValue.toLowerCase().trim(); - return switch (operator.toUpperCase()) { - case "EQ", "=", "EQUALS" -> actual.equals(expected); - case "NEQ", "!=", "<>", "NOT_EQUALS" -> !actual.equals(expected); - case "CONTAINS", "LIKE" -> actual.contains(expected); - case "NOT_CONTAINS", "NOT_LIKE" -> !actual.contains(expected); - case "STARTS_WITH" -> actual.startsWith(expected); - case "ENDS_WITH" -> actual.endsWith(expected); - case "IN" -> Arrays.stream(expected.split(",")).map(String::trim).anyMatch(v -> v.equals(actual)); - case "NOT_IN" -> Arrays.stream(expected.split(",")).map(String::trim).noneMatch(v -> v.equals(actual)); - case "GT", ">" -> { - try { yield Double.parseDouble(actual) > Double.parseDouble(expected); } - catch (NumberFormatException e) { yield false; } - } - case "GTE", ">=" -> { - try { yield Double.parseDouble(actual) >= Double.parseDouble(expected); } - catch (NumberFormatException e) { yield false; } - } - case "LT", "<" -> { - try { yield Double.parseDouble(actual) < Double.parseDouble(expected); } - catch (NumberFormatException e) { yield false; } - } - case "LTE", "<=" -> { - try { yield Double.parseDouble(actual) <= Double.parseDouble(expected); } - catch (NumberFormatException e) { yield false; } - } - case "IS_NULL", "NULL" -> actual.isEmpty() || "null".equals(actual) || "undefined".equals(actual); - case "IS_NOT_NULL", "NOT_NULL" -> !actual.isEmpty() && !"null".equals(actual) && !"undefined".equals(actual); - default -> { - log.warn("알 수 없는 연산자: {}", operator); - yield false; - } - }; - } -} diff --git a/backend-spring/src/main/java/com/erp/service/CascadingHierarchyService.java b/backend-spring/src/main/java/com/erp/service/CascadingHierarchyService.java deleted file mode 100644 index abda63c1..00000000 --- a/backend-spring/src/main/java/com/erp/service/CascadingHierarchyService.java +++ /dev/null @@ -1,251 +0,0 @@ -package com.erp.service; - -import com.erp.common.BaseService; -import lombok.RequiredArgsConstructor; -import lombok.extern.slf4j.Slf4j; -import org.springframework.jdbc.core.JdbcTemplate; -import org.springframework.stereotype.Service; -import org.springframework.transaction.annotation.Transactional; -import java.util.*; - -@Service -@RequiredArgsConstructor -@Slf4j -public class CascadingHierarchyService extends BaseService { - - private static final String NS = "cascadingHierarchy."; - - private final CommonService commonService; - private final JdbcTemplate jdbcTemplate; - - public Map getCascadingHierarchyGroupList(Map params) { - commonService.applyCompanyCodeFilter(params); - commonService.applyPagination(params); - int totalCount = sqlSession.selectOne(NS + "getCascadingHierarchyGroupListCnt", params); - List> list = sqlSession.selectList(NS + "getCascadingHierarchyGroupList", params); - return commonService.buildListResponse(list, totalCount, params); - } - - public Map getCascadingHierarchyGroupDetail(Map params) { - commonService.applyCompanyCodeFilter(params); - Map group = sqlSession.selectOne(NS + "getCascadingHierarchyGroupByCode", params); - if (group == null) return null; - - Map levelParams = new HashMap<>(); - levelParams.put("group_code", params.get("group_code")); - levelParams.put("company_code", group.get("company_code")); - List> levels = sqlSession.selectList(NS + "getCascadingHierarchyLevelList", levelParams); - - Map result = new HashMap<>(group); - result.put("levels", levels); - return result; - } - - @Transactional - public Map insertCascadingHierarchyGroup(Map params) { - commonService.applyCompanyCodeFilter(params); - String companyCode = (String) params.get("company_code"); - String userId = (String) params.getOrDefault("user_id", "system"); - - // Generate group code: HG_{timestamp_base36}_{count:03d} - Map countParams = new HashMap<>(); - countParams.put("company_code", companyCode); - Number cntNum = sqlSession.selectOne(NS + "getCascadingHierarchyGroupCount", countParams); - int count = (cntNum != null ? cntNum.intValue() : 0) + 1; - String timestamp = Long.toString(System.currentTimeMillis(), 36).toUpperCase(); - String suffix = timestamp.substring(Math.max(0, timestamp.length() - 4)); - String groupCode = "HG_" + suffix + "_" + String.format("%03d", count); - - params.put("group_code", groupCode); - params.put("created_by", userId); - - if (params.get("hierarchy_type") == null) params.put("hierarchy_type", "MULTI_TABLE"); - if (params.get("is_fixed_levels") == null) params.put("is_fixed_levels", "Y"); - if (params.get("empty_message") == null) params.put("empty_message", "선택해주세요"); - if (params.get("no_options_message") == null) params.put("no_options_message", "옵션이 없습니다"); - if (params.get("loading_message") == null) params.put("loading_message", "로딩 중..."); - - sqlSession.insert(NS + "insertCascadingHierarchyGroup", params); - - // Insert levels for MULTI_TABLE type - Object levelsObj = params.get("levels"); - if ("MULTI_TABLE".equals(params.get("hierarchy_type")) && levelsObj instanceof List) { - List levels = (List) levelsObj; - for (Object l : levels) { - if (l instanceof Map) { - @SuppressWarnings("unchecked") - Map level = (Map) l; - Map lp = new HashMap<>(level); - lp.put("group_code", groupCode); - lp.put("company_code", companyCode); - if (lp.get("order_direction") == null) lp.put("order_direction", "ASC"); - if (lp.get("is_required") == null) lp.put("is_required", "Y"); - if (lp.get("is_searchable") == null) lp.put("is_searchable", "N"); - if (lp.get("placeholder") == null && lp.get("level_name") != null) { - lp.put("placeholder", lp.get("level_name") + " 선택"); - } - sqlSession.insert(NS + "insertCascadingHierarchyLevel", lp); - } - } - } - return params; - } - - @Transactional - public Map updateCascadingHierarchyGroup(Map params) { - commonService.applyCompanyCodeFilter(params); - params.put("updated_by", params.getOrDefault("user_id", "system")); - - Map existing = sqlSession.selectOne(NS + "getCascadingHierarchyGroupByCode", params); - if (existing == null) return null; - - params.put("company_code", existing.get("company_code")); - sqlSession.update(NS + "updateCascadingHierarchyGroup", params); - return params; - } - - @Transactional - public boolean deleteCascadingHierarchyGroup(Map params) { - commonService.applyCompanyCodeFilter(params); - Map existing = sqlSession.selectOne(NS + "getCascadingHierarchyGroupByCode", params); - if (existing == null) return false; - - String groupCode = (String) params.get("group_code"); - String companyCode = (String) existing.get("company_code"); - - Map delParams = new HashMap<>(); - delParams.put("group_code", groupCode); - delParams.put("company_code", companyCode); - sqlSession.delete(NS + "deleteCascadingHierarchyLevels", delParams); - sqlSession.delete(NS + "deleteCascadingHierarchyGroup", delParams); - return true; - } - - @Transactional - public Map addCascadingHierarchyLevel(Map params) { - commonService.applyCompanyCodeFilter(params); - String groupCode = (String) params.get("group_code"); - - Map groupParams = new HashMap<>(); - groupParams.put("group_code", groupCode); - groupParams.put("company_code", params.get("company_code")); - Map group = sqlSession.selectOne(NS + "getCascadingHierarchyGroupByCode", groupParams); - if (group == null) return null; - - params.put("company_code", group.get("company_code")); - if (params.get("order_direction") == null) params.put("order_direction", "ASC"); - if (params.get("is_required") == null) params.put("is_required", "Y"); - if (params.get("is_searchable") == null) params.put("is_searchable", "N"); - if (params.get("placeholder") == null && params.get("level_name") != null) { - params.put("placeholder", params.get("level_name") + " 선택"); - } - - sqlSession.insert(NS + "insertCascadingHierarchyLevel", params); - return params; - } - - @Transactional - public Map updateCascadingHierarchyLevel(Map params) { - commonService.applyCompanyCodeFilter(params); - Map existing = sqlSession.selectOne(NS + "getCascadingHierarchyLevelInfo", params); - if (existing == null) return null; - - sqlSession.update(NS + "updateCascadingHierarchyLevel", params); - return params; - } - - @Transactional - public boolean deleteCascadingHierarchyLevel(Map params) { - commonService.applyCompanyCodeFilter(params); - Map existing = sqlSession.selectOne(NS + "getCascadingHierarchyLevelInfo", params); - if (existing == null) return false; - - sqlSession.delete(NS + "deleteCascadingHierarchyLevel", params); - return true; - } - - public Map getLevelOptions(Map params) { - commonService.applyCompanyCodeFilter(params); - String companyCode = (String) params.get("company_code"); - - Map level = sqlSession.selectOne(NS + "getCascadingHierarchyLevelForOptions", params); - if (level == null) return null; - - String tableName = sanitizeIdentifier((String) level.get("table_name")); - String valueColumn = sanitizeIdentifier((String) level.get("value_column")); - String labelColumn = sanitizeIdentifier((String) level.get("label_column")); - - StringBuilder sql = new StringBuilder(); - sql.append("SELECT ").append(valueColumn).append(" AS value, ") - .append(labelColumn).append(" AS label") - .append(" FROM ").append(tableName) - .append(" WHERE 1=1"); - - List sqlParams = new ArrayList<>(); - - // Parent value filter (level 2+) - Object parentValue = params.get("parent_value"); - Object parentKeyColumn = level.get("parent_key_column"); - if (parentKeyColumn != null && !parentKeyColumn.toString().isEmpty() && parentValue != null) { - sql.append(" AND ").append(sanitizeIdentifier(parentKeyColumn.toString())).append(" = ?"); - sqlParams.add(parentValue); - } - - // Fixed filter - Object filterColumn = level.get("filter_column"); - Object filterValue = level.get("filter_value"); - if (filterColumn != null && !filterColumn.toString().isEmpty() - && filterValue != null && !filterValue.toString().isEmpty()) { - sql.append(" AND ").append(sanitizeIdentifier(filterColumn.toString())).append(" = ?"); - sqlParams.add(filterValue.toString()); - } - - // Multi-tenancy - if (!"*".equals(companyCode) && hasColumn(tableName, "company_code")) { - sql.append(" AND company_code = ?"); - sqlParams.add(companyCode); - } - - // Order - Object orderColumn = level.get("order_column"); - if (orderColumn != null && !orderColumn.toString().isEmpty()) { - Object orderDir = level.get("order_direction"); - String dir = (orderDir != null && "DESC".equalsIgnoreCase(orderDir.toString())) ? "DESC" : "ASC"; - sql.append(" ORDER BY ").append(sanitizeIdentifier(orderColumn.toString())).append(" ").append(dir); - } else { - sql.append(" ORDER BY ").append(labelColumn); - } - - List> options = jdbcTemplate.queryForList(sql.toString(), sqlParams.toArray()); - - Map levelInfo = new LinkedHashMap<>(); - levelInfo.put("level_id", level.get("level_id")); - levelInfo.put("level_name", level.get("level_name")); - levelInfo.put("placeholder", level.get("placeholder")); - levelInfo.put("is_required", level.get("is_required")); - levelInfo.put("is_searchable", level.get("is_searchable")); - - Map result = new HashMap<>(); - result.put("data", options); - result.put("level_info", levelInfo); - return result; - } - - private String sanitizeIdentifier(String identifier) { - if (identifier == null || !identifier.matches("[a-zA-Z0-9_.]+")) { - throw new IllegalArgumentException("Invalid SQL identifier: " + identifier); - } - return identifier; - } - - private boolean hasColumn(String tableName, String columnName) { - try { - Integer count = jdbcTemplate.queryForObject( - "SELECT COUNT(*) FROM information_schema.columns WHERE table_name = ? AND column_name = ?", - Integer.class, tableName, columnName); - return count != null && count > 0; - } catch (Exception e) { - return false; - } - } -} diff --git a/backend-spring/src/main/java/com/erp/service/CascadingMutualExclusionService.java b/backend-spring/src/main/java/com/erp/service/CascadingMutualExclusionService.java deleted file mode 100644 index c06c5bb9..00000000 --- a/backend-spring/src/main/java/com/erp/service/CascadingMutualExclusionService.java +++ /dev/null @@ -1,175 +0,0 @@ -package com.erp.service; - -import com.erp.common.BaseService; -import lombok.RequiredArgsConstructor; -import lombok.extern.slf4j.Slf4j; -import org.springframework.jdbc.core.JdbcTemplate; -import org.springframework.stereotype.Service; -import org.springframework.transaction.annotation.Transactional; -import java.util.*; - -@Service -@RequiredArgsConstructor -@Slf4j -public class CascadingMutualExclusionService extends BaseService { - - private static final String NS = "cascadingMutualExclusion."; - - private final CommonService commonService; - private final JdbcTemplate jdbcTemplate; - - public Map getCascadingMutualExclusionList(Map params) { - commonService.applyCompanyCodeFilter(params); - commonService.applyPagination(params); - int totalCount = sqlSession.selectOne(NS + "getCascadingMutualExclusionListCnt", params); - List> list = sqlSession.selectList(NS + "getCascadingMutualExclusionList", params); - return commonService.buildListResponse(list, totalCount, params); - } - - public Map getCascadingMutualExclusionInfo(Map params) { - commonService.applyCompanyCodeFilter(params); - return sqlSession.selectOne(NS + "getCascadingMutualExclusionInfo", params); - } - - @Transactional - public Map insertCascadingMutualExclusion(Map params) { - commonService.applyCompanyCodeFilter(params); - if (params.get("exclusion_type") == null) params.put("exclusion_type", "SAME_VALUE"); - if (params.get("error_message") == null) params.put("error_message", "동일한 값을 선택할 수 없습니다"); - - // 배제 코드 자동 생성: EX_XXXX_NNN - String companyCode = (String) params.get("company_code"); - Map countParams = new LinkedHashMap<>(); - countParams.put("company_code", companyCode); - int count = sqlSession.selectOne(NS + "getCascadingMutualExclusionCount", countParams); - String ts = Long.toString(System.currentTimeMillis(), 36).toUpperCase(); - ts = ts.substring(Math.max(0, ts.length() - 4)); - params.put("exclusion_code", String.format("EX_%s_%03d", ts, count + 1)); - - sqlSession.insert(NS + "insertCascadingMutualExclusion", params); - return params; - } - - @Transactional - public Map updateCascadingMutualExclusion(Map params) { - commonService.applyCompanyCodeFilter(params); - sqlSession.update(NS + "updateCascadingMutualExclusion", params); - return params; - } - - @Transactional - public Map deleteCascadingMutualExclusion(Map params) { - commonService.applyCompanyCodeFilter(params); - sqlSession.delete(NS + "deleteCascadingMutualExclusion", params); - return params; - } - - /** - * 상호 배제 검증: 선택한 값들 간 충돌 여부 확인 (SAME_VALUE 타입) - */ - public Map validateCascadingMutualExclusion(Map params) { - commonService.applyCompanyCodeFilter(params); - Map exclusion = sqlSession.selectOne(NS + "getCascadingMutualExclusionByCode", params); - if (exclusion == null) throw new NoSuchElementException("상호 배제 규칙을 찾을 수 없습니다."); - - @SuppressWarnings("unchecked") - Map fieldValues = (Map) params.getOrDefault("field_values", Collections.emptyMap()); - - String fieldNamesStr = (String) exclusion.get("field_names"); - String[] fields = fieldNamesStr != null ? fieldNamesStr.split(",") : new String[0]; - - List values = new ArrayList<>(); - for (String field : fields) { - Object v = fieldValues.get(field.trim()); - if (v != null) values.add(v.toString()); - } - - boolean isValid = true; - String errorMessage = null; - List conflictingFields = new ArrayList<>(); - - String exclusionType = (String) exclusion.getOrDefault("exclusion_type", "SAME_VALUE"); - if ("SAME_VALUE".equals(exclusionType)) { - Set seen = new LinkedHashSet<>(); - boolean hasDuplicate = false; - for (String v : values) { - if (!seen.add(v)) { hasDuplicate = true; break; } - } - if (hasDuplicate) { - isValid = false; - errorMessage = (String) exclusion.get("error_message"); - Map> valueCounts = new LinkedHashMap<>(); - for (String field : fields) { - Object v = fieldValues.get(field.trim()); - if (v != null) { - valueCounts.computeIfAbsent(v.toString(), k -> new ArrayList<>()).add(field.trim()); - } - } - for (List fl : valueCounts.values()) { - if (fl.size() > 1) { conflictingFields = fl; break; } - } - } - } - - Map result = new LinkedHashMap<>(); - result.put("is_valid", isValid); - result.put("error_message", isValid ? null : errorMessage); - result.put("conflicting_fields", conflictingFields); - return result; - } - - /** - * 배제 옵션 조회: source_table에서 이미 선택된 값을 제외한 목록 반환 - */ - public List> getExcludedOptions(Map params) { - commonService.applyCompanyCodeFilter(params); - String companyCode = (String) params.get("company_code"); - - Map exclusion = sqlSession.selectOne(NS + "getCascadingMutualExclusionByCode", params); - if (exclusion == null) throw new NoSuchElementException("상호 배제 규칙을 찾을 수 없습니다."); - - String sourceTable = (String) exclusion.get("source_table"); - String valueColumn = (String) exclusion.get("value_column"); - String labelColumn = (String) exclusion.get("label_column"); - if (labelColumn == null || labelColumn.isEmpty()) labelColumn = valueColumn; - - boolean hasCompanyCode = hasColumn(sourceTable, "company_code"); - - List queryParams = new ArrayList<>(); - StringBuilder sql = new StringBuilder(); - sql.append("SELECT ") - .append(valueColumn).append(" AS value, ") - .append(labelColumn).append(" AS label") - .append(" FROM ").append(sourceTable) - .append(" WHERE 1=1"); - - if (hasCompanyCode && !"*".equals(companyCode)) { - sql.append(" AND company_code = ?"); - queryParams.add(companyCode); - } - - Object selectedValuesParam = params.get("selected_values"); - if (selectedValuesParam != null) { - List excludeValues = new ArrayList<>(); - for (String v : selectedValuesParam.toString().split(",")) { - String trimmed = v.trim(); - if (!trimmed.isEmpty()) excludeValues.add(trimmed); - } - if (!excludeValues.isEmpty()) { - String placeholders = String.join(", ", Collections.nCopies(excludeValues.size(), "?")); - sql.append(" AND ").append(valueColumn).append(" NOT IN (").append(placeholders).append(")"); - queryParams.addAll(excludeValues); - } - } - - sql.append(" ORDER BY ").append(labelColumn); - - return jdbcTemplate.queryForList(sql.toString(), queryParams.toArray()); - } - - private boolean hasColumn(String tableName, String columnName) { - String sql = "SELECT COUNT(*) FROM information_schema.columns WHERE table_name = ? AND column_name = ?"; - Integer count = jdbcTemplate.queryForObject(sql, Integer.class, tableName, columnName); - return count != null && count > 0; - } -} diff --git a/backend-spring/src/main/java/com/erp/service/CascadingRelationService.java b/backend-spring/src/main/java/com/erp/service/CascadingRelationService.java deleted file mode 100644 index 7b340f30..00000000 --- a/backend-spring/src/main/java/com/erp/service/CascadingRelationService.java +++ /dev/null @@ -1,193 +0,0 @@ -package com.erp.service; - -import com.erp.common.BaseService; -import lombok.extern.slf4j.Slf4j; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.jdbc.core.JdbcTemplate; -import org.springframework.stereotype.Service; -import org.springframework.transaction.annotation.Transactional; -import java.util.*; - -@Service -@Slf4j -public class CascadingRelationService extends BaseService { - - private static final String NS = "cascadingRelation."; - - @Autowired - private CommonService commonService; - @Autowired - private JdbcTemplate jdbcTemplate; - - public Map getCascadingRelationList(Map params) { - commonService.applyCompanyCodeFilter(params); - commonService.applyPagination(params); - int totalCount = sqlSession.selectOne(NS + "getCascadingRelationListCnt", params); - List> list = sqlSession.selectList(NS + "getCascadingRelationList", params); - return commonService.buildListResponse(list, totalCount, params); - } - - public Map getCascadingRelationInfo(Map params) { - commonService.applyCompanyCodeFilter(params); - return sqlSession.selectOne(NS + "getCascadingRelationInfo", params); - } - - public Map getCascadingRelationByCode(Map params) { - commonService.applyCompanyCodeFilter(params); - return sqlSession.selectOne(NS + "getCascadingRelationByCode", params); - } - - @Transactional - public Map insertCascadingRelation(Map params) { - commonService.applyCompanyCodeFilter(params); - if (params.get("empty_parent_message") == null) - params.put("empty_parent_message", "상위 항목을 먼저 선택하세요"); - if (params.get("no_options_message") == null) - params.put("no_options_message", "선택 가능한 항목이 없습니다"); - if (params.get("loading_message") == null) - params.put("loading_message", "로딩 중..."); - if (params.get("child_order_direction") == null) - params.put("child_order_direction", "ASC"); - Object clearOnParentChange = params.get("clear_on_parent_change"); - if (clearOnParentChange == null) { - params.put("clear_on_parent_change", "Y"); - } else if (clearOnParentChange instanceof Boolean) { - params.put("clear_on_parent_change", Boolean.TRUE.equals(clearOnParentChange) ? "Y" : "N"); - } - params.put("is_active", "Y"); - sqlSession.insert(NS + "insertCascadingRelation", params); - return params; - } - - @Transactional - public Map updateCascadingRelation(Map params) { - commonService.applyCompanyCodeFilter(params); - Object isActive = params.get("is_active"); - if (isActive instanceof Boolean) { - params.put("is_active", Boolean.TRUE.equals(isActive) ? "Y" : "N"); - } - Object clearOnParentChange = params.get("clear_on_parent_change"); - if (clearOnParentChange instanceof Boolean) { - params.put("clear_on_parent_change", Boolean.TRUE.equals(clearOnParentChange) ? "Y" : "N"); - } - sqlSession.update(NS + "updateCascadingRelation", params); - return params; - } - - @Transactional - public Map deleteCascadingRelation(Map params) { - commonService.applyCompanyCodeFilter(params); - sqlSession.update(NS + "deleteCascadingRelation", params); - return params; - } - - /** - * 부모 옵션 조회: relation_code로 관계 조회 후 parent_table에서 동적 쿼리 - */ - public List> getParentOptions(Map params) { - String companyCode = (String) params.get("company_code"); - - Map relation = sqlSession.selectOne(NS + "getCascadingRelationByCode", params); - if (relation == null) { - throw new NoSuchElementException("연쇄 관계를 찾을 수 없습니다."); - } - - String parentTable = (String) relation.get("parent_table"); - String parentValueColumn = (String) relation.get("parent_value_column"); - String parentLabelColumn = (String) relation.get("parent_label_column"); - if (parentLabelColumn == null || parentLabelColumn.isEmpty()) { - parentLabelColumn = parentValueColumn; - } - - boolean hasCompanyCode = hasColumn(parentTable, "company_code"); - boolean hasStatus = hasColumn(parentTable, "status"); - - List queryParams = new ArrayList<>(); - StringBuilder sql = new StringBuilder(); - sql.append("SELECT ") - .append(parentValueColumn).append(" AS value, ") - .append(parentLabelColumn).append(" AS label") - .append(" FROM ").append(parentTable) - .append(" WHERE 1=1"); - - if (hasCompanyCode && !"*".equals(companyCode)) { - sql.append(" AND company_code = ?"); - queryParams.add(companyCode); - } - if (hasStatus) { - sql.append(" AND (status IS NULL OR status != 'N')"); - } - sql.append(" ORDER BY ").append(parentLabelColumn).append(" ASC"); - - return jdbcTemplate.queryForList(sql.toString(), queryParams.toArray()); - } - - /** - * 연쇄 옵션 조회: relation_code로 관계 조회 후 child_table에서 동적 쿼리 - * parentValue(단일) 또는 parentValues(콤마 구분 다중) 지원 - */ - public List> getCascadingOptions(Map params) { - String companyCode = (String) params.get("company_code"); - Object parentValueParam = params.get("parent_value"); - Object parentValuesParam = params.get("parent_values"); - - List parentValueArray = new ArrayList<>(); - if (parentValuesParam != null) { - for (String v : parentValuesParam.toString().split(",")) { - String trimmed = v.trim(); - if (!trimmed.isEmpty()) parentValueArray.add(trimmed); - } - } else if (parentValueParam != null) { - parentValueArray.add(parentValueParam.toString()); - } - - if (parentValueArray.isEmpty()) { - return Collections.emptyList(); - } - - Map relation = sqlSession.selectOne(NS + "getCascadingRelationByCode", params); - if (relation == null) { - throw new NoSuchElementException("연쇄 관계를 찾을 수 없습니다."); - } - - String childTable = (String) relation.get("child_table"); - String childFilterColumn = (String) relation.get("child_filter_column"); - String childValueColumn = (String) relation.get("child_value_column"); - String childLabelColumn = (String) relation.get("child_label_column"); - String childOrderColumn = (String) relation.get("child_order_column"); - String childOrderDir = (String) relation.get("child_order_direction"); - if (childOrderDir == null || childOrderDir.isEmpty()) childOrderDir = "ASC"; - - boolean hasCompanyCode = hasColumn(childTable, "company_code"); - - List queryParams = new ArrayList<>(parentValueArray); - String placeholders = String.join(", ", Collections.nCopies(parentValueArray.size(), "?")); - - StringBuilder sql = new StringBuilder(); - sql.append("SELECT DISTINCT ") - .append(childValueColumn).append(" AS value, ") - .append(childLabelColumn).append(" AS label, ") - .append(childFilterColumn).append(" AS parent_value") - .append(" FROM ").append(childTable) - .append(" WHERE ").append(childFilterColumn).append(" IN (").append(placeholders).append(")"); - - if (hasCompanyCode && !"*".equals(companyCode)) { - sql.append(" AND company_code = ?"); - queryParams.add(companyCode); - } - - if (childOrderColumn != null && !childOrderColumn.isEmpty()) { - sql.append(" ORDER BY ").append(childOrderColumn).append(" ").append(childOrderDir); - } else { - sql.append(" ORDER BY ").append(childLabelColumn).append(" ASC"); - } - - return jdbcTemplate.queryForList(sql.toString(), queryParams.toArray()); - } - - private boolean hasColumn(String tableName, String columnName) { - String sql = "SELECT COUNT(*) FROM information_schema.columns WHERE table_name = ? AND column_name = ?"; - Integer count = jdbcTemplate.queryForObject(sql, Integer.class, tableName, columnName); - return count != null && count > 0; - } -} diff --git a/backend-spring/src/main/java/com/erp/service/CategoryTreeService.java b/backend-spring/src/main/java/com/erp/service/CategoryTreeService.java deleted file mode 100644 index c3025146..00000000 --- a/backend-spring/src/main/java/com/erp/service/CategoryTreeService.java +++ /dev/null @@ -1,415 +0,0 @@ -package com.erp.service; - -import com.erp.common.BaseService; -import lombok.extern.slf4j.Slf4j; -import org.springframework.stereotype.Service; -import org.springframework.transaction.annotation.Transactional; - -import java.util.*; - -@Service -@Slf4j -public class CategoryTreeService extends BaseService { - - private static final String NS = "categoryTree."; - - private Long toLong(Object val) { - if (val == null) return null; - if (val instanceof Number n) return n.longValue(); - try { return Long.parseLong(val.toString()); } catch (Exception e) { return null; } - } - - /** - * 카테고리 트리 조회 (플랫 리스트 → 트리 변환) - */ - public List> getCategoryTreeList(String companyCode, String tableName, String columnName) { - Map params = new HashMap<>(); - params.put("company_code", companyCode); - params.put("table_name", tableName); - params.put("column_name", columnName); - List> flatList = sqlSession.selectList(NS + "getCategoryTreeList", params); - return buildTree(flatList); - } - - /** - * 카테고리 플랫 리스트 조회 - */ - public List> getCategoryTreeFlatList(String companyCode, String tableName, String columnName) { - Map params = new HashMap<>(); - params.put("company_code", companyCode); - params.put("table_name", tableName); - params.put("column_name", columnName); - return sqlSession.selectList(NS + "getCategoryTreeList", params); - } - - /** - * 카테고리 값 단건 조회 - */ - public Map getCategoryTreeInfo(String companyCode, int valueId) { - Map params = new HashMap<>(); - params.put("company_code", companyCode); - params.put("value_id", valueId); - return sqlSession.selectOne(NS + "getCategoryTreeInfo", params); - } - - /** - * 카테고리 값 생성 - */ - @Transactional - public Map insertCategoryTree(Map body, String companyCode, String createdBy) { - String tableName = (String) body.get("table_name"); - String columnName = (String) body.get("column_name"); - String valueCode = (String) body.get("value_code"); - String valueLabel = (String) body.get("value_label"); - - Object valueOrderRaw = body.get("value_order"); - int valueOrder = valueOrderRaw != null ? ((Number) valueOrderRaw).intValue() : 0; - - Object parentValueIdRaw = body.get("parent_value_id"); - - // depth / path 계산 - int depth = 1; - String path = valueLabel; - - if (parentValueIdRaw != null) { - Map parentParams = new HashMap<>(); - parentParams.put("company_code", companyCode); - parentParams.put("value_id", ((Number) parentValueIdRaw).intValue()); - Map parent = sqlSession.selectOne(NS + "getCategoryTreeInfo", parentParams); - if (parent != null) { - depth = ((Number) parent.get("depth")).intValue() + 1; - if (depth > 3) { - throw new IllegalArgumentException("카테고리는 최대 3단계까지만 가능합니다"); - } - String parentPath = (String) parent.get("path"); - path = parentPath != null ? parentPath + "/" + valueLabel : valueLabel; - } - } - - Map params = new HashMap<>(); - params.put("table_name", tableName); - params.put("column_name", columnName); - params.put("value_code", valueCode); - params.put("value_label", valueLabel); - params.put("value_order", valueOrder); - params.put("parent_value_id", parentValueIdRaw); - params.put("depth", depth); - params.put("path", path); - params.put("description", body.get("description")); - params.put("color", body.get("color")); - params.put("icon", body.get("icon")); - - Object isActiveRaw = body.get("is_active"); - Object isDefaultRaw = body.get("is_default"); - params.put("is_active", isActiveRaw != null ? isActiveRaw : true); - params.put("is_default", isDefaultRaw != null ? isDefaultRaw : false); - - params.put("company_code", companyCode); - params.put("created_by", createdBy); - - sqlSession.insert(NS + "insertCategoryTree", params); - - // useGeneratedKeys → params.get("value_id") 에 생성된 ID 저장 - Map fetchParams = new HashMap<>(); - fetchParams.put("company_code", companyCode); - fetchParams.put("value_id", params.get("value_id")); - return sqlSession.selectOne(NS + "getCategoryTreeInfo", fetchParams); - } - - /** - * 카테고리 값 수정 - */ - @Transactional - public Map updateCategoryTree(String companyCode, int valueId, - Map body, String updatedBy) { - Map currentParams = new HashMap<>(); - currentParams.put("company_code", companyCode); - currentParams.put("value_id", valueId); - Map current = sqlSession.selectOne(NS + "getCategoryTreeInfo", currentParams); - if (current == null) return null; - - String currentLabel = (String) current.get("value_label"); - int currentDepth = ((Number) current.get("depth")).intValue(); - String currentPath = (String) current.get("path"); - Object currentParentId = current.get("parent_value_id"); - - String newLabel = body.containsKey("value_label") ? (String) body.get("value_label") : currentLabel; - int newDepth = currentDepth; - String newPath = currentPath; - Object newParentId = body.containsKey("parent_value_id") ? body.get("parent_value_id") : currentParentId; - - boolean labelChanged = body.containsKey("value_label") - && !Objects.equals(newLabel, currentLabel); - boolean parentChanged = body.containsKey("parent_value_id") - && !Objects.equals(toLong(body.get("parent_value_id")), toLong(currentParentId)); - - if (parentChanged) { - if (body.get("parent_value_id") != null) { - Map newParentParams = new HashMap<>(); - newParentParams.put("company_code", companyCode); - newParentParams.put("value_id", ((Number) body.get("parent_value_id")).intValue()); - Map newParent = sqlSession.selectOne(NS + "getCategoryTreeInfo", newParentParams); - if (newParent != null) { - newDepth = ((Number) newParent.get("depth")).intValue() + 1; - if (newDepth > 3) { - throw new IllegalArgumentException("카테고리는 최대 3단계까지만 가능합니다"); - } - String parentPath = (String) newParent.get("path"); - newPath = parentPath != null ? parentPath + "/" + newLabel : newLabel; - } - } else { - newDepth = 1; - newPath = newLabel; - } - } else if (labelChanged) { - if (currentParentId != null) { - Map parentParams = new HashMap<>(); - parentParams.put("company_code", companyCode); - parentParams.put("value_id", ((Number) currentParentId).intValue()); - Map parent = sqlSession.selectOne(NS + "getCategoryTreeInfo", parentParams); - String parentPath = parent != null ? (String) parent.get("path") : null; - newPath = parentPath != null ? parentPath + "/" + newLabel : newLabel; - } else { - newPath = newLabel; - } - } - - Map updateParams = new HashMap<>(); - updateParams.put("company_code", companyCode); - updateParams.put("value_id", valueId); - updateParams.put("value_code", body.get("value_code")); - updateParams.put("value_label", body.containsKey("value_label") ? newLabel : null); - updateParams.put("value_order", body.get("value_order")); - updateParams.put("parent_value_id", newParentId); - updateParams.put("depth", newDepth); - updateParams.put("path", newPath); - updateParams.put("description", body.get("description")); - updateParams.put("color", body.get("color")); - updateParams.put("icon", body.get("icon")); - updateParams.put("is_active", body.get("is_active")); - updateParams.put("is_default", body.get("is_default")); - updateParams.put("updated_by", updatedBy); - - int affected = sqlSession.update(NS + "updateCategoryTree", updateParams); - if (affected == 0) return null; - - if (labelChanged || parentChanged) { - updateChildrenPaths(companyCode, valueId, newPath != null ? newPath : ""); - } - - Map fetchParams = new HashMap<>(); - fetchParams.put("company_code", companyCode); - fetchParams.put("value_id", valueId); - return sqlSession.selectOne(NS + "getCategoryTreeInfo", fetchParams); - } - - /** - * 카테고리 값 삭제 가능 여부 사전 확인 - */ - public Map checkCanDelete(String companyCode, int valueId) { - Map value = getCategoryTreeInfo(companyCode, valueId); - if (value == null) { - Map res = new LinkedHashMap<>(); - res.put("can_delete", false); - res.put("reason", "카테고리 값을 찾을 수 없습니다"); - return res; - } - - Map childParams = new HashMap<>(); - childParams.put("value_id", valueId); - childParams.put("company_code", companyCode); - Integer childCountObj = sqlSession.selectOne(NS + "getCategoryTreeChildrenCnt", childParams); - int childCount = childCountObj != null ? childCountObj : 0; - if (childCount > 0) { - Map res = new LinkedHashMap<>(); - res.put("can_delete", false); - res.put("reason", "하위 카테고리가 " + childCount + "개 존재합니다. 하위 카테고리를 먼저 삭제해주세요."); - return res; - } - - Map usage = checkCategoryValueInUse(companyCode, value); - boolean inUse = Boolean.TRUE.equals(usage.get("in_use")); - if (inUse) { - int count = ((Number) usage.get("count")).intValue(); - Map res = new LinkedHashMap<>(); - res.put("can_delete", false); - res.put("reason", "이 카테고리 값(" + value.get("value_label") + ")은 " + count + "건의 데이터에서 사용 중이므로 삭제할 수 없습니다."); - return res; - } - - Map res = new LinkedHashMap<>(); - res.put("can_delete", true); - return res; - } - - /** - * 카테고리 값 삭제 (자식·사용 여부 검증 후 삭제) - */ - @Transactional - public boolean deleteCategoryTree(String companyCode, int valueId) { - Map value = getCategoryTreeInfo(companyCode, valueId); - if (value == null) return false; - - // 1. 자식 존재 여부 - Map childParams = new HashMap<>(); - childParams.put("value_id", valueId); - childParams.put("company_code", companyCode); - Integer childCountObj = sqlSession.selectOne(NS + "getCategoryTreeChildrenCnt", childParams); - int childCount = childCountObj != null ? childCountObj : 0; - if (childCount > 0) { - throw new IllegalStateException( - "VALIDATION:하위 카테고리가 " + childCount + "개 존재합니다. 하위 카테고리를 먼저 삭제해주세요."); - } - - // 2. 실제 데이터 사용 여부 - Map usage = checkCategoryValueInUse(companyCode, value); - boolean inUse = Boolean.TRUE.equals(usage.get("in_use")); - if (inUse) { - int count = ((Number) usage.get("count")).intValue(); - throw new IllegalStateException( - "VALIDATION:이 카테고리 값(" + value.get("value_label") + ")은 " - + value.get("table_name") + " 테이블에서 " + count + "건의 데이터가 사용 중이므로 삭제할 수 없습니다."); - } - - // 3. 삭제 - Map deleteParams = new HashMap<>(); - deleteParams.put("company_code", companyCode); - deleteParams.put("value_id", valueId); - return sqlSession.delete(NS + "deleteCategoryTree", deleteParams) > 0; - } - - /** - * 테이블의 카테고리 컬럼 목록 조회 - */ - public List> getCategoryTreeColumnList(String companyCode, String tableName) { - Map params = new HashMap<>(); - params.put("table_name", tableName); - params.put("company_code", companyCode); - return sqlSession.selectList(NS + "getCategoryTreeColumnList", params); - } - - /** - * 전체 카테고리 키 목록 조회 (모든 테이블.컬럼 조합) - */ - public List> getCategoryTreeKeyList(String companyCode) { - Map params = new HashMap<>(); - params.put("company_code", companyCode); - return sqlSession.selectList(NS + "getCategoryTreeKeyList", params); - } - - // ─── private helpers ──────────────────────────────────────────────────────── - - /** - * 플랫 리스트 → 트리 구조 변환 - */ - private List> buildTree(List> flatList) { - Map> map = new LinkedHashMap<>(); - List> roots = new ArrayList<>(); - - for (Map item : flatList) { - Map node = new LinkedHashMap<>(item); - node.put("children", new ArrayList<>()); - map.put(item.get("value_id"), node); - } - - for (Map item : flatList) { - Object parentId = item.get("parent_value_id"); - Map node = map.get(item.get("value_id")); - if (parentId != null && map.containsKey(parentId)) { - @SuppressWarnings("unchecked") - List> children = - (List>) map.get(parentId).get("children"); - children.add(node); - } else { - roots.add(node); - } - } - - return roots; - } - - /** - * 하위 항목들의 path 재귀 업데이트 - */ - private void updateChildrenPaths(String companyCode, int parentValueId, String parentPath) { - Map params = new HashMap<>(); - params.put("company_code", companyCode); - params.put("parent_value_id", parentValueId); - - List> children = sqlSession.selectList(NS + "getCategoryTreeChildrenList", params); - for (Map child : children) { - String valueLabel = (String) child.get("value_label"); - String newPath = parentPath + "/" + valueLabel; - - Map updateParams = new HashMap<>(); - updateParams.put("value_id", child.get("value_id")); - updateParams.put("path", newPath); - sqlSession.update(NS + "updateCategoryTreeChildPath", updateParams); - - int childId = ((Number) child.get("value_id")).intValue(); - updateChildrenPaths(companyCode, childId, newPath); - } - } - - /** - * 카테고리 값이 실제 데이터 테이블에서 사용 중인지 확인 - * 오류 발생 시 무시하고 삭제 허용 (Node.js 동일 동작) - */ - private Map checkCategoryValueInUse(String companyCode, Map value) { - String tableName = (String) value.get("table_name"); - String columnName = (String) value.get("column_name"); - String valueCode = (String) value.get("value_code"); - - Map notInUse = Map.of("in_use", false, "count", 0); - - try { - // 1. 테이블 존재 확인 - Map tableParams = new HashMap<>(); - tableParams.put("table_name", tableName); - Integer teObj = sqlSession.selectOne(NS + "checkTableExists", tableParams); - if (teObj == null || teObj == 0) return notInUse; - - // 2. 컬럼 존재 확인 - Map colParams = new HashMap<>(); - colParams.put("table_name", tableName); - colParams.put("column_name", columnName); - Integer ceObj = sqlSession.selectOne(NS + "checkColumnExists", colParams); - if (ceObj == null || ceObj == 0) return notInUse; - - // 3. company_code 컬럼 존재 확인 - Map companyColParams = new HashMap<>(); - companyColParams.put("table_name", tableName); - companyColParams.put("column_name", "company_code"); - Integer ccObj = sqlSession.selectOne(NS + "checkColumnExists", companyColParams); - boolean hasCompanyCode = ccObj != null && ccObj > 0; - - // 4. 사용 건수 조회 - int count; - if (hasCompanyCode && !"*".equals(companyCode)) { - Map countParams = new HashMap<>(); - countParams.put("table_name", tableName); - countParams.put("column_name", columnName); - countParams.put("company_code", companyCode); - countParams.put("value_code", valueCode); - Integer cntObj = sqlSession.selectOne(NS + "countCategoryUsageWithCompany", countParams); - count = cntObj != null ? cntObj : 0; - } else { - Map countParams = new HashMap<>(); - countParams.put("table_name", tableName); - countParams.put("column_name", columnName); - countParams.put("value_code", valueCode); - Integer cntObj = sqlSession.selectOne(NS + "countCategoryUsage", countParams); - count = cntObj != null ? cntObj : 0; - } - - Map result = new HashMap<>(); - result.put("in_use", count > 0); - result.put("count", count); - return result; - - } catch (Exception e) { - log.warn("카테고리 사용 여부 확인 중 오류 (무시하고 삭제 허용): {}", e.getMessage()); - return notInUse; - } - } -} diff --git a/backend-spring/src/main/java/com/erp/service/CategoryValueCascadingService.java b/backend-spring/src/main/java/com/erp/service/CategoryValueCascadingService.java deleted file mode 100644 index 475ee5ca..00000000 --- a/backend-spring/src/main/java/com/erp/service/CategoryValueCascadingService.java +++ /dev/null @@ -1,270 +0,0 @@ -package com.erp.service; - -import com.erp.common.BaseService; -import lombok.extern.slf4j.Slf4j; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.jdbc.core.JdbcTemplate; -import org.springframework.stereotype.Service; -import org.springframework.transaction.annotation.Transactional; -import java.util.*; -import java.util.stream.Collectors; - -@Service -@Slf4j -public class CategoryValueCascadingService extends BaseService { - - private static final String NS = "categoryValueCascading."; - - @Autowired - private CommonService commonService; - @Autowired - private JdbcTemplate jdbcTemplate; - - public Map getCategoryValueCascadingGroupList(Map params) { - commonService.applyCompanyCodeFilter(params); - commonService.applyPagination(params); - int totalCount = sqlSession.selectOne(NS + "getCategoryValueCascadingGroupListCnt", params); - List> list = sqlSession.selectList(NS + "getCategoryValueCascadingGroupList", params); - return commonService.buildListResponse(list, totalCount, params); - } - - public Map getCategoryValueCascadingGroupInfo(Map params) { - commonService.applyCompanyCodeFilter(params); - Map group = sqlSession.selectOne(NS + "getCategoryValueCascadingGroupInfo", params); - if (group == null) return null; - - List> mappings = sqlSession.selectList(NS + "getCategoryValueCascadingMappingsByGroupId", params); - - Map>> mappingsByParent = new LinkedHashMap<>(); - for (Map m : mappings) { - String parentKey = String.valueOf(m.get("parent_value_code")); - mappingsByParent.computeIfAbsent(parentKey, k -> new ArrayList<>()).add(Map.of( - "child_value_code", m.getOrDefault("child_value_code", ""), - "child_value_label", m.getOrDefault("child_value_label", ""), - "display_order", m.getOrDefault("display_order", 0) - )); - } - - Map result = new LinkedHashMap<>(group); - result.put("mappings", mappings); - result.put("mappings_by_parent", mappingsByParent); - return result; - } - - public Map getCategoryValueCascadingGroupByCode(Map params) { - commonService.applyCompanyCodeFilter(params); - return sqlSession.selectOne(NS + "getCategoryValueCascadingGroupByCode", params); - } - - @Transactional - public Map insertCategoryValueCascadingGroup(Map params) { - commonService.applyCompanyCodeFilter(params); - sqlSession.insert(NS + "insertCategoryValueCascadingGroup", params); - return params; - } - - @Transactional - public Map updateCategoryValueCascadingGroup(Map params) { - commonService.applyCompanyCodeFilter(params); - sqlSession.update(NS + "updateCategoryValueCascadingGroup", params); - return params; - } - - @Transactional - public Map deleteCategoryValueCascadingGroup(Map params) { - commonService.applyCompanyCodeFilter(params); - sqlSession.update(NS + "deleteCategoryValueCascadingGroup", params); - return params; - } - - @Transactional - @SuppressWarnings("unchecked") - public Map saveCategoryValueCascadingMappings(Map params) { - commonService.applyCompanyCodeFilter(params); - String companyCode = (String) params.get("company_code"); - Object groupId = params.get("group_id"); - - sqlSession.delete(NS + "deleteCategoryValueCascadingMappingsByGroupId", params); - - int savedCount = 0; - Object mappingsObj = params.get("mappings"); - if (mappingsObj instanceof List) { - List> mappings = (List>) mappingsObj; - for (Map mapping : mappings) { - Map mappingParams = new HashMap<>(mapping); - mappingParams.put("group_id", groupId); - mappingParams.put("company_code", companyCode); - sqlSession.insert(NS + "insertCategoryValueCascadingMapping", mappingParams); - savedCount++; - } - } - - Map result = new LinkedHashMap<>(); - result.put("saved_count", savedCount); - result.put("group_id", groupId); - return result; - } - - public Map getCategoryValueCascadingParentOptions(Map params) { - commonService.applyCompanyCodeFilter(params); - String companyCode = (String) params.get("company_code"); - - Map group = sqlSession.selectOne(NS + "getCategoryValueCascadingGroupByCode", params); - if (group == null) { - Map result = new LinkedHashMap<>(); - result.put("data", Collections.emptyList()); - return result; - } - - String tableName = String.valueOf(group.get("parent_table_name")); - String columnName = String.valueOf(group.get("parent_column_name")); - Object menuObjid = group.get("parent_menu_objid"); - - StringBuilder sql = new StringBuilder( - "SELECT value_code as value, value_label as label, value_order as display_order" + - " FROM category_values WHERE table_name = ? AND column_name = ? AND is_active = true"); - List sqlParams = new ArrayList<>(Arrays.asList(tableName, columnName)); - - if (menuObjid != null) { - sql.append(" AND menu_objid = ?"); - sqlParams.add(menuObjid); - } - if (companyCode != null && !"*".equals(companyCode)) { - sql.append(" AND (company_code = ? OR company_code = '*')"); - sqlParams.add(companyCode); - } - sql.append(" ORDER BY value_order, value_label"); - - List> options = jdbcTemplate.queryForList(sql.toString(), sqlParams.toArray()); - Map result = new LinkedHashMap<>(); - result.put("data", options); - return result; - } - - public Map getCategoryValueCascadingChildOptions(Map params) { - commonService.applyCompanyCodeFilter(params); - String companyCode = (String) params.get("company_code"); - - Map group = sqlSession.selectOne(NS + "getCategoryValueCascadingGroupByCode", params); - if (group == null) { - Map result = new LinkedHashMap<>(); - result.put("data", Collections.emptyList()); - return result; - } - - String tableName = String.valueOf(group.get("child_table_name")); - String columnName = String.valueOf(group.get("child_column_name")); - Object menuObjid = group.get("child_menu_objid"); - - StringBuilder sql = new StringBuilder( - "SELECT value_code as value, value_label as label, value_order as display_order" + - " FROM category_values WHERE table_name = ? AND column_name = ? AND is_active = true"); - List sqlParams = new ArrayList<>(Arrays.asList(tableName, columnName)); - - if (menuObjid != null) { - sql.append(" AND menu_objid = ?"); - sqlParams.add(menuObjid); - } - if (companyCode != null && !"*".equals(companyCode)) { - sql.append(" AND (company_code = ? OR company_code = '*')"); - sqlParams.add(companyCode); - } - sql.append(" ORDER BY value_order, value_label"); - - List> options = jdbcTemplate.queryForList(sql.toString(), sqlParams.toArray()); - Map result = new LinkedHashMap<>(); - result.put("data", options); - return result; - } - - public Map getCategoryValueCascadingOptions(Map params) { - commonService.applyCompanyCodeFilter(params); - - String parentValuesStr = params.get("parent_values") != null ? String.valueOf(params.get("parent_values")) : null; - String parentValue = params.get("parent_value") != null ? String.valueOf(params.get("parent_value")) : null; - - List parentValueArray = new ArrayList<>(); - if (parentValuesStr != null && !parentValuesStr.isEmpty()) { - for (String v : parentValuesStr.split(",")) { - String trimmed = v.trim(); - if (!trimmed.isEmpty()) parentValueArray.add(trimmed); - } - } else if (parentValue != null && !parentValue.isEmpty()) { - parentValueArray.add(parentValue); - } - - if (parentValueArray.isEmpty()) { - Map result = new LinkedHashMap<>(); - result.put("data", Collections.emptyList()); - return result; - } - - Map group = sqlSession.selectOne(NS + "getCategoryValueCascadingGroupByCode", params); - if (group == null) { - Map result = new LinkedHashMap<>(); - result.put("data", Collections.emptyList()); - return result; - } - - Object groupId = group.get("group_id"); - String showGroupLabel = group.get("show_group_label") != null ? String.valueOf(group.get("show_group_label")) : "N"; - - String placeholders = parentValueArray.stream().map(v -> "?").collect(Collectors.joining(", ")); - String sql = "SELECT DISTINCT child_value_code as value, child_value_label as label," + - " parent_value_code as parent_value, parent_value_label as parent_label, display_order" + - " FROM category_value_cascading_mapping" + - " WHERE group_id = ? AND parent_value_code IN (" + placeholders + ") AND is_active = 'Y'" + - " ORDER BY parent_value_code, display_order, child_value_label"; - - List sqlParams = new ArrayList<>(); - sqlParams.add(groupId); - sqlParams.addAll(parentValueArray); - - List> options = jdbcTemplate.queryForList(sql, sqlParams.toArray()); - Map result = new LinkedHashMap<>(); - result.put("data", options); - result.put("show_group_label", "Y".equals(showGroupLabel)); - return result; - } - - public Map getCategoryValueCascadingMappingsByTable(Map params) { - commonService.applyCompanyCodeFilter(params); - String companyCode = (String) params.get("company_code"); - String tableName = (String) params.get("table_name"); - - StringBuilder groupSql = new StringBuilder( - "SELECT group_id, relation_code, child_column_name" + - " FROM category_value_cascading_group" + - " WHERE child_table_name = ? AND is_active = 'Y'"); - List groupSqlParams = new ArrayList<>(); - groupSqlParams.add(tableName); - - if (companyCode != null && !"*".equals(companyCode)) { - groupSql.append(" AND (company_code = ? OR company_code = '*')"); - groupSqlParams.add(companyCode); - } - - List> groups = jdbcTemplate.queryForList(groupSql.toString(), groupSqlParams.toArray()); - - Map mappings = new LinkedHashMap<>(); - for (Map group : groups) { - Object groupId = group.get("group_id"); - String childColumnName = String.valueOf(group.get("child_column_name")); - - List> groupMappings = jdbcTemplate.queryForList( - "SELECT DISTINCT child_value_code as code, child_value_label as label" + - " FROM category_value_cascading_mapping" + - " WHERE group_id = ? AND is_active = 'Y'" + - " ORDER BY child_value_label", - groupId); - - if (!groupMappings.isEmpty()) { - mappings.put(childColumnName, groupMappings); - } - } - - Map result = new LinkedHashMap<>(); - result.put("data", mappings); - return result; - } -} diff --git a/backend-spring/src/main/java/com/erp/service/CodeMergeService.java b/backend-spring/src/main/java/com/erp/service/CodeMergeService.java deleted file mode 100644 index 0b4f6bc8..00000000 --- a/backend-spring/src/main/java/com/erp/service/CodeMergeService.java +++ /dev/null @@ -1,247 +0,0 @@ -package com.erp.service; - -import com.erp.common.BaseService; -import lombok.RequiredArgsConstructor; -import lombok.extern.slf4j.Slf4j; -import org.springframework.jdbc.core.JdbcTemplate; -import org.springframework.stereotype.Service; -import org.springframework.transaction.annotation.Transactional; - -import java.util.*; -import java.util.stream.Collectors; - -@Service -@RequiredArgsConstructor -@Slf4j -public class CodeMergeService extends BaseService { - - private final JdbcTemplate jdbcTemplate; - - private static final String NS = "codeMerge."; - - // ── Tables With Column ──────────────────────────────────────────────────── - - /** - * GET /tables-with-column/:columnName - * 해당 컬럼과 company_code 컬럼을 함께 가진 public 테이블 목록 반환 - */ - public Map getTablesWithColumn(String columnName) { - Map params = new HashMap<>(); - params.put("column_name", columnName); - List> rows = sqlSession.selectList(NS + "getTablesWithColumn", params); - - List tables = rows.stream() - .map(r -> { - Object val = r.get("table_name"); - return val != null ? val.toString() : null; - }) - .filter(Objects::nonNull) - .collect(Collectors.toList()); - - Map result = new LinkedHashMap<>(); - result.put("column_name", columnName); - result.put("tables", tables); - result.put("count", tables.size()); - return result; - } - - // ── Preview (column-based) ──────────────────────────────────────────────── - - /** - * POST /preview - * columnName + oldValue 기준으로 영향받을 테이블/행 수 미리보기 (DB 변경 없음) - */ - public Map previewCodeMerge(Map body) { - String columnName = str(body.get("column_name")); - String oldValue = str(body.get("old_value")); - String companyCode = str(body.get("company_code")); - - if (isBlank(columnName) || isBlank(oldValue)) { - throw new IllegalArgumentException("필수 필드가 누락되었습니다. (columnName, oldValue)"); - } - - log.info("코드 병합 미리보기: column={}, oldValue={}, company={}", columnName, oldValue, companyCode); - - Map params = new HashMap<>(); - params.put("column_name", columnName); - List> tableRows = sqlSession.selectList(NS + "getTablesWithColumn", params); - - List> preview = new ArrayList<>(); - int totalRows = 0; - - for (Map tableRow : tableRows) { - Object nameVal = tableRow.get("table_name"); - if (nameVal == null) continue; - String tableName = nameVal.toString(); - - // 테이블명·컬럼명은 information_schema에서 검증된 값 — SQL 인젝션 위험 없음 - String countSql = String.format( - "SELECT COUNT(*) FROM \"%s\" WHERE \"%s\" = ? AND company_code = ?", - tableName, columnName); - try { - Integer count = jdbcTemplate.queryForObject(countSql, Integer.class, oldValue, companyCode); - if (count != null && count > 0) { - Map item = new LinkedHashMap<>(); - item.put("table_name", tableName); - item.put("affected_rows", count); - preview.add(item); - totalRows += count; - } - } catch (Exception e) { - log.warn("테이블 {} 조회 실패 (건너뜀): {}", tableName, e.getMessage()); - } - } - - Map result = new LinkedHashMap<>(); - result.put("column_name", columnName); - result.put("old_value", oldValue); - result.put("preview", preview); - result.put("total_affected_rows", totalRows); - return result; - } - - // ── Merge All Tables (column-based) ─────────────────────────────────────── - - /** - * POST /merge-all-tables - * PostgreSQL 함수 merge_code_all_tables(columnName, oldValue, newValue, companyCode) 호출 - */ - @Transactional - public Map mergeAllTables(Map body) { - String columnName = str(body.get("column_name")); - String oldValue = str(body.get("old_value")); - String newValue = str(body.get("new_value")); - String companyCode = str(body.get("company_code")); - - if (isBlank(columnName) || isBlank(oldValue) || isBlank(newValue)) { - throw new IllegalArgumentException("필수 필드가 누락되었습니다. (columnName, oldValue, newValue)"); - } - if (oldValue.equals(newValue)) { - throw new IllegalArgumentException("기존 값과 새 값이 동일합니다."); - } - - log.info("코드 병합 시작: column={}, {} → {}, company={}", columnName, oldValue, newValue, companyCode); - - List> rows = jdbcTemplate.queryForList( - "SELECT * FROM merge_code_all_tables(?, ?, ?, ?)", - columnName, oldValue, newValue, companyCode); - - int totalRows = rows.stream() - .mapToInt(r -> r.get("rows_updated") != null ? ((Number) r.get("rows_updated")).intValue() : 0) - .sum(); - - List> affectedTables = rows.stream().map(r -> { - Map item = new LinkedHashMap<>(); - item.put("table_name", r.get("table_name")); - item.put("rows_updated", r.get("rows_updated") != null ? ((Number) r.get("rows_updated")).intValue() : 0); - return item; - }).collect(Collectors.toList()); - - log.info("코드 병합 완료: 영향 테이블 {}개, 총 {}행", affectedTables.size(), totalRows); - - Map result = new LinkedHashMap<>(); - result.put("column_name", columnName); - result.put("old_value", oldValue); - result.put("new_value", newValue); - result.put("affected_tables", affectedTables); - result.put("total_rows_updated", totalRows); - return result; - } - - // ── Merge By Value ──────────────────────────────────────────────────────── - - /** - * POST /merge-by-value - * PostgreSQL 함수 merge_code_by_value(oldValue, newValue, companyCode) 호출 - * 컬럼명에 관계없이 해당 값을 가진 모든 위치를 변경 - */ - @Transactional - public Map mergeByValue(Map body) { - String oldValue = str(body.get("old_value")); - String newValue = str(body.get("new_value")); - String companyCode = str(body.get("company_code")); - - if (isBlank(oldValue) || isBlank(newValue)) { - throw new IllegalArgumentException("필수 필드가 누락되었습니다. (oldValue, newValue)"); - } - if (oldValue.equals(newValue)) { - throw new IllegalArgumentException("기존 값과 새 값이 동일합니다."); - } - - log.info("값 기반 코드 병합 시작: {} → {}, company={}", oldValue, newValue, companyCode); - - List> rows = jdbcTemplate.queryForList( - "SELECT * FROM merge_code_by_value(?, ?, ?)", - oldValue, newValue, companyCode); - - int totalRows = rows.stream() - .mapToInt(r -> r.get("out_rows_updated") != null ? ((Number) r.get("out_rows_updated")).intValue() : 0) - .sum(); - - List> affectedData = rows.stream().map(r -> { - Map item = new LinkedHashMap<>(); - item.put("table_name", r.get("out_table_name")); - item.put("column_name", r.get("out_column_name")); - item.put("rows_updated", r.get("out_rows_updated") != null ? ((Number) r.get("out_rows_updated")).intValue() : 0); - return item; - }).collect(Collectors.toList()); - - log.info("값 기반 코드 병합 완료: {} → {}, 총 {}행", oldValue, newValue, totalRows); - - Map result = new LinkedHashMap<>(); - result.put("old_value", oldValue); - result.put("new_value", newValue); - result.put("affected_data", affectedData); - result.put("total_rows_updated", totalRows); - return result; - } - - // ── Preview By Value ────────────────────────────────────────────────────── - - /** - * POST /preview-by-value - * PostgreSQL 함수 preview_merge_code_by_value(oldValue, companyCode) 호출 - */ - public Map previewByValue(Map body) { - String oldValue = str(body.get("old_value")); - String companyCode = str(body.get("company_code")); - - if (isBlank(oldValue)) { - throw new IllegalArgumentException("필수 필드가 누락되었습니다. (oldValue)"); - } - - log.info("값 기반 코드 병합 미리보기: oldValue={}, company={}", oldValue, companyCode); - - List> rows = jdbcTemplate.queryForList( - "SELECT * FROM preview_merge_code_by_value(?, ?)", - oldValue, companyCode); - - int totalRows = rows.stream() - .mapToInt(r -> r.get("out_affected_rows") != null ? ((Number) r.get("out_affected_rows")).intValue() : 0) - .sum(); - - List> preview = rows.stream().map(r -> { - Map item = new LinkedHashMap<>(); - item.put("table_name", r.get("out_table_name")); - item.put("column_name", r.get("out_column_name")); - item.put("affected_rows", r.get("out_affected_rows") != null ? ((Number) r.get("out_affected_rows")).intValue() : 0); - return item; - }).collect(Collectors.toList()); - - Map result = new LinkedHashMap<>(); - result.put("old_value", oldValue); - result.put("preview", preview); - result.put("total_affected_rows", totalRows); - return result; - } - - // ── Helpers ─────────────────────────────────────────────────────────────── - - private String str(Object val) { - return val != null ? val.toString() : null; - } - - private boolean isBlank(String s) { - return s == null || s.isBlank(); - } -} diff --git a/backend-spring/src/main/java/com/erp/service/CommonCodeService.java b/backend-spring/src/main/java/com/erp/service/CommonCodeService.java index 99156036..b0dc23e3 100644 --- a/backend-spring/src/main/java/com/erp/service/CommonCodeService.java +++ b/backend-spring/src/main/java/com/erp/service/CommonCodeService.java @@ -8,10 +8,12 @@ import org.springframework.transaction.annotation.Transactional; import java.util.*; /** - * Common Code Service + * Common Code Service — 마스터-디테일 패턴. * - * commonCodeRoutes.ts 포팅. - * 테이블: code_category, code_info + * • code_info : 1레벨 그룹 마스터 (PK = code_info + company_code) + * • code_detail : 2레벨 ~ 무한대 트리 (PK = code_detail_id, parent_detail_id 로 self-ref) + * + * 옛 캐스케이딩/카테고리 구조 폐기. 단일 그룹 안에서 재귀 트리. */ @Service @Slf4j @@ -19,13 +21,11 @@ public class CommonCodeService extends BaseService { private static final String NS = "commonCode."; - private static final long DEFAULT_MENU_OBJID = 1757401858940L; - // ══════════════════════════════════════════════════════════════ - // 카테고리 목록 + // CODE_INFO — 그룹 마스터 CRUD // ══════════════════════════════════════════════════════════════ - public Map getCommonCodeCategoryList(Map params) { + public Map getCodeInfoList(Map params) { int page = toInt(params.get("page"), 1); int size = toInt(params.get("size"), 20); params.put("limit", size); @@ -34,425 +34,273 @@ public class CommonCodeService extends BaseService { Object isActiveRaw = params.get("is_active"); if (isActiveRaw != null) params.put("is_active", toActiveStr(isActiveRaw)); - List> categories = sqlSession.selectList(NS + "getCommonCodeCategoryList", params); - Integer totalObj = sqlSession.selectOne(NS + "getCommonCodeCategoryListCnt", params); + List> data = sqlSession.selectList(NS + "getCodeInfoList", params); + Integer totalObj = sqlSession.selectOne(NS + "getCodeInfoListCnt", params); int total = totalObj != null ? totalObj : 0; Map result = new LinkedHashMap<>(); - result.put("data", categories); + result.put("data", data); result.put("total", total); return result; } - // ══════════════════════════════════════════════════════════════ - // 카테고리 중복 확인 - // ══════════════════════════════════════════════════════════════ - - public Map checkCategoryDuplicate(String field, String value, - String excludeCode, String companyCode) { - if (value == null || value.trim().isEmpty()) { - Map result = new LinkedHashMap<>(); - result.put("is_duplicate", false); - result.put("message", "값을 입력해주세요."); - return result; - } - + public Map getCodeInfoInfo(String codeInfo, String companyCode) { Map params = new HashMap<>(); - params.put("field", field != null ? field : "category_code"); - params.put("value", value.trim()); - params.put("exclude_code", excludeCode); + params.put("code_info", codeInfo); params.put("company_code", companyCode); - Integer countObj = sqlSession.selectOne(NS + "getCommonCodeCategoryDuplicateByField", params); - boolean isDuplicate = countObj != null && countObj > 0; - - Map result = new LinkedHashMap<>(); - result.put("is_duplicate", isDuplicate); - result.put("message", isDuplicate ? "이미 사용 중인 값입니다." : "사용 가능한 값입니다."); - return result; + return sqlSession.selectOne(NS + "getCodeInfoInfo", params); } - // ══════════════════════════════════════════════════════════════ - // 카테고리 생성 - // ══════════════════════════════════════════════════════════════ - @Transactional - public Map insertCommonCodeCategory(Map body, String companyCode, String userId) { + public Map insertCodeInfo(Map body, String companyCode, String userId) { Map params = new HashMap<>(); - params.put("category_code", body.get("category_code")); - params.put("category_name", body.get("category_name")); - params.put("category_name_eng", body.getOrDefault("category_name_eng", null)); - params.put("description", body.getOrDefault("description", null)); - params.put("sort_order", body.getOrDefault("sort_order", 0)); - params.put("is_active", toActiveStr(body.getOrDefault("is_active", true))); - params.put("menu_objid", body.getOrDefault("menu_objid", DEFAULT_MENU_OBJID)); - params.put("company_code", companyCode); - params.put("created_by", userId); - params.put("updated_by", userId); - - sqlSession.insert(NS + "insertCommonCodeCategory", params); - - Map q = new HashMap<>(); - q.put("category_code", params.get("category_code")); - q.put("company_code", companyCode); - return sqlSession.selectOne(NS + "getCommonCodeCategoryInfo", q); - } - - // ══════════════════════════════════════════════════════════════ - // 카테고리 수정 - // ══════════════════════════════════════════════════════════════ - - @Transactional - public Map updateCommonCodeCategory(String categoryCode, Map body, - String companyCode, String userId) { - Map params = new HashMap<>(); - params.put("category_code", categoryCode); + params.put("code_info", body.get("code_info")); + params.put("code_name", body.get("code_name")); + params.put("code_name_eng", body.getOrDefault("code_name_eng", null)); + params.put("description", body.getOrDefault("description", null)); + params.put("sort_order", body.getOrDefault("sort_order", 0)); + params.put("is_active", toActiveStr(body.getOrDefault("is_active", true))); + params.put("menu_objid", body.getOrDefault("menu_objid", null)); params.put("company_code", companyCode); + params.put("created_by", userId); params.put("updated_by", userId); - if (body.containsKey("category_name")) params.put("category_name", body.get("category_name")); - if (body.containsKey("category_name_eng")) params.put("category_name_eng", body.get("category_name_eng")); - if (body.containsKey("description")) params.put("description", body.get("description")); - if (body.containsKey("sort_order")) params.put("sort_order", body.get("sort_order")); - if (body.containsKey("is_active")) params.put("is_active", toActiveStr(body.get("is_active"))); + sqlSession.insert(NS + "insertCodeInfo", params); - int updated = sqlSession.update(NS + "updateCommonCodeCategory", params); - if (updated == 0) return null; - - Map q = new HashMap<>(); - q.put("category_code", categoryCode); - q.put("company_code", companyCode); - return sqlSession.selectOne(NS + "getCommonCodeCategoryInfo", q); + return getCodeInfoInfo(String.valueOf(params.get("code_info")), companyCode); } - // ══════════════════════════════════════════════════════════════ - // 카테고리 삭제 - // ══════════════════════════════════════════════════════════════ - @Transactional - public void deleteCommonCodeCategory(String categoryCode, String companyCode) { + public Map updateCodeInfo(String codeInfo, Map body, + String companyCode, String userId) { Map params = new HashMap<>(); - params.put("category_code", categoryCode); - params.put("company_code", companyCode); - int deleted = sqlSession.delete(NS + "deleteCommonCodeCategory", params); - if (deleted == 0) throw new IllegalArgumentException("카테고리를 찾을 수 없습니다."); + params.put("code_info", codeInfo); + params.put("company_code", companyCode); + params.put("updated_by", userId); + + if (body.containsKey("code_name")) params.put("code_name", body.get("code_name")); + if (body.containsKey("code_name_eng")) params.put("code_name_eng", body.get("code_name_eng")); + if (body.containsKey("description")) params.put("description", body.get("description")); + if (body.containsKey("sort_order")) params.put("sort_order", body.get("sort_order")); + if (body.containsKey("is_active")) params.put("is_active", toActiveStr(body.get("is_active"))); + if (body.containsKey("menu_objid")) params.put("menu_objid", body.get("menu_objid")); + + int updated = sqlSession.update(NS + "updateCodeInfo", params); + if (updated == 0) return null; + + return getCodeInfoInfo(codeInfo, companyCode); } - // ══════════════════════════════════════════════════════════════ - // 코드 목록 (snake_case + camelCase 이중 필드) - // ══════════════════════════════════════════════════════════════ + @Transactional + public void deleteCodeInfo(String codeInfo, String companyCode) { + Map params = new HashMap<>(); + params.put("code_info", codeInfo); + params.put("company_code", companyCode); - public Map getCommonCodeList(String categoryCode, Map params) { - int page = toInt(params.get("page"), 1); - int size = toInt(params.get("size"), 20); - params.put("category_code", categoryCode); - params.put("limit", size); - params.put("offset", (page - 1) * size); - - Object isActiveRaw = params.get("is_active"); - if (isActiveRaw != null) params.put("is_active", toActiveStr(isActiveRaw)); - - List> rawList = sqlSession.selectList(NS + "getCommonCodeList", params); - Integer totalObj = sqlSession.selectOne(NS + "getCommonCodeListCnt", params); - int total = totalObj != null ? totalObj : 0; - - List> codes = new ArrayList<>(); - for (Map raw : rawList) { - codes.add(transformCode(raw)); - } + int deleted = sqlSession.delete(NS + "deleteCodeInfo", params); + if (deleted == 0) throw new IllegalArgumentException("코드 그룹을 찾을 수 없습니다."); + } + public Map checkCodeInfoDuplicate(String field, String value, + String excludeCode, String companyCode) { Map result = new LinkedHashMap<>(); - result.put("data", codes); - result.put("total", total); - return result; - } - - // ══════════════════════════════════════════════════════════════ - // 코드 중복 확인 - // ══════════════════════════════════════════════════════════════ - - public Map checkCodeDuplicate(String categoryCode, String field, String value, - String excludeCode, String companyCode) { if (value == null || value.trim().isEmpty()) { - Map result = new LinkedHashMap<>(); result.put("is_duplicate", false); - result.put("message", "값을 입력해주세요."); + result.put("message", "값을 입력해주세요."); return result; } Map params = new HashMap<>(); - params.put("category_code", categoryCode); - params.put("field", field != null ? field : "code_value"); + params.put("field", field != null ? field : "code_info"); params.put("value", value.trim()); - params.put("exclude_code", excludeCode); - params.put("company_code", companyCode); - Integer countObj = sqlSession.selectOne(NS + "getCommonCodeDuplicateByField", params); + params.put("exclude_code", excludeCode); + params.put("company_code", companyCode); + + Integer countObj = sqlSession.selectOne(NS + "getCodeInfoDuplicateByField", params); boolean isDuplicate = countObj != null && countObj > 0; - Map result = new LinkedHashMap<>(); result.put("is_duplicate", isDuplicate); result.put("message", isDuplicate ? "이미 사용 중인 값입니다." : "사용 가능한 값입니다."); return result; } // ══════════════════════════════════════════════════════════════ - // 코드 생성 + // CODE_DETAIL — 디테일 트리 CRUD // ══════════════════════════════════════════════════════════════ - @Transactional - public Map insertCommonCode(String categoryCode, Map body, - String companyCode, String userId) { - // parentCodeValue 기반 depth 자동 계산 - Object parentCodeValueRaw = body.getOrDefault("parent_code_value", null); - int depth = 1; - if (parentCodeValueRaw != null && !parentCodeValueRaw.toString().isEmpty()) { - Map parentParams = new HashMap<>(); - parentParams.put("category_code", categoryCode); - parentParams.put("code_value", parentCodeValueRaw.toString()); - parentParams.put("company_code", companyCode); - Integer parentDepth = sqlSession.selectOne(NS + "getCommonCodeParentDepth", parentParams); - depth = (parentDepth != null ? parentDepth : 0) + 1; - } - - Map params = new HashMap<>(); - params.put("category_code", categoryCode); - params.put("code_value", body.get("code_value")); - params.put("code_name", body.get("code_name")); - params.put("code_name_eng", body.getOrDefault("code_name_eng", null)); - params.put("description", body.getOrDefault("description", null)); - params.put("sort_order", body.getOrDefault("sort_order", 0)); - params.put("is_active", toActiveStr(body.getOrDefault("is_active", true))); - params.put("menu_objid", body.getOrDefault("menu_objid", DEFAULT_MENU_OBJID)); - params.put("company_code", companyCode); - params.put("parent_code_value", parentCodeValueRaw); - params.put("depth", depth); - params.put("created_by", userId); - params.put("updated_by", userId); - - sqlSession.insert(NS + "insertCommonCode", params); - - Map q = new HashMap<>(); - q.put("category_code", categoryCode); - q.put("code_value", params.get("code_value")); - q.put("company_code", companyCode); - Map raw = sqlSession.selectOne(NS + "getCommonCodeInfo", q); - return raw != null ? transformCode(raw) : null; - } - - // ══════════════════════════════════════════════════════════════ - // 코드 정렬 순서 변경 - // ══════════════════════════════════════════════════════════════ - - @Transactional - public void updateCommonCodeOrder(String categoryCode, List> codes, String companyCode) { - for (Map code : codes) { - Map params = new HashMap<>(); - params.put("category_code", categoryCode); - params.put("code_value", code.get("code_value")); - params.put("sort_order", code.get("sort_order")); - params.put("company_code", companyCode); - sqlSession.update(NS + "updateCommonCodeSortOrder", params); - } - } - - // ══════════════════════════════════════════════════════════════ - // 계층형 코드 목록 - // ══════════════════════════════════════════════════════════════ - - public List> getCommonCodeHierarchicalList(String categoryCode, Map params) { - params.put("category_code", categoryCode); + public Map getCodeDetailList(String codeInfo, Map params) { + int page = toInt(params.get("page"), 1); + int size = toInt(params.get("size"), 20); + params.put("code_info", codeInfo); + params.put("limit", size); + params.put("offset", (page - 1) * size); Object isActiveRaw = params.get("is_active"); if (isActiveRaw != null) params.put("is_active", toActiveStr(isActiveRaw)); - else params.remove("is_active"); - // parentCodeValue, depth 필터는 params에 그대로 전달 (XML에서 처리) - - List> rawList = sqlSession.selectList(NS + "getCommonCodeHierarchicalList", params); - List> result = new ArrayList<>(); - for (Map raw : rawList) { - result.add(transformCode(raw)); + Object parentRaw = params.get("parent_detail_id"); + if (parentRaw != null && !parentRaw.toString().isEmpty()) { + params.put("parent_detail_id", toLong(parentRaw)); + } else { + params.remove("parent_detail_id"); } - return result; - } - // ══════════════════════════════════════════════════════════════ - // 트리 구조 — { flat: [...], tree: [...] } - // ══════════════════════════════════════════════════════════════ - - public Map getCommonCodeTree(String categoryCode, String companyCode) { - Map params = new HashMap<>(); - params.put("category_code", categoryCode); - params.put("company_code", companyCode); - - List> flatList = sqlSession.selectList(NS + "getCommonCodeTreeList", params); - - List> flatTransformed = new ArrayList<>(); - for (Map raw : flatList) { - flatTransformed.add(transformCode(raw)); - } + List> data = sqlSession.selectList(NS + "getCodeDetailList", params); + Integer totalObj = sqlSession.selectOne(NS + "getCodeDetailListCnt", params); + int total = totalObj != null ? totalObj : 0; Map result = new LinkedHashMap<>(); - result.put("flat", flatTransformed); - result.put("tree", buildTree(flatList)); + result.put("data", data); + result.put("total", total); return result; } - // ══════════════════════════════════════════════════════════════ - // 자식 존재 여부 - // ══════════════════════════════════════════════════════════════ - - public Map hasChildren(String categoryCode, String codeValue, String companyCode) { + /** + * 그룹 전체 트리 — 평탄화된 리스트로 반환 (depth + sort_order 순). + * 프론트가 parent_detail_id 로 nest 처리하기 좋게. + */ + public List> getCodeDetailTree(String codeInfo, String companyCode) { Map params = new HashMap<>(); - params.put("category_code", categoryCode); - params.put("code_value", codeValue); - params.put("company_code", companyCode); - Integer countObj = sqlSession.selectOne(NS + "getCommonCodeChildrenCnt", params); + params.put("code_info", codeInfo); + params.put("company_code", companyCode); + return sqlSession.selectList(NS + "getCodeDetailTree", params); + } + + public Map getCodeDetailInfo(Long codeDetailId, String companyCode) { + Map params = new HashMap<>(); + params.put("code_detail_id", codeDetailId); + params.put("company_code", companyCode); + return sqlSession.selectOne(NS + "getCodeDetailInfo", params); + } + + @Transactional + public Map insertCodeDetail(String codeInfo, Map body, + String companyCode, String userId) { + // parent_detail_id 기반 depth 자동 계산. NULL = 그룹 직속 (depth=2). + Long parentDetailId = toLong(body.getOrDefault("parent_detail_id", null)); + int depth = 2; + if (parentDetailId != null) { + Map parentParams = new HashMap<>(); + parentParams.put("code_detail_id", parentDetailId); + parentParams.put("company_code", companyCode); + Integer parentDepth = sqlSession.selectOne(NS + "getCodeDetailParentDepth", parentParams); + depth = (parentDepth != null ? parentDepth : 1) + 1; + } + + Map params = new HashMap<>(); + params.put("code_info", codeInfo); + params.put("parent_detail_id", parentDetailId); + params.put("code_value", body.get("code_value")); + params.put("code_name", body.get("code_name")); + params.put("code_name_eng", body.getOrDefault("code_name_eng", null)); + params.put("description", body.getOrDefault("description", null)); + params.put("depth", depth); + params.put("sort_order", body.getOrDefault("sort_order", 0)); + params.put("is_active", toActiveStr(body.getOrDefault("is_active", true))); + params.put("company_code", companyCode); + params.put("created_by", userId); + params.put("updated_by", userId); + + sqlSession.insert(NS + "insertCodeDetail", params); + + Object newIdRaw = params.get("code_detail_id"); + Long newId = toLong(newIdRaw); + return newId != null ? getCodeDetailInfo(newId, companyCode) : null; + } + + @Transactional + public Map updateCodeDetail(Long codeDetailId, Map body, + String companyCode, String userId) { + Map params = new HashMap<>(); + params.put("code_detail_id", codeDetailId); + params.put("company_code", companyCode); + params.put("updated_by", userId); + + if (body.containsKey("code_value")) params.put("code_value", body.get("code_value")); + if (body.containsKey("code_name")) params.put("code_name", body.get("code_name")); + if (body.containsKey("code_name_eng")) params.put("code_name_eng", body.get("code_name_eng")); + if (body.containsKey("description")) params.put("description", body.get("description")); + if (body.containsKey("sort_order")) params.put("sort_order", body.get("sort_order")); + if (body.containsKey("is_active")) params.put("is_active", toActiveStr(body.get("is_active"))); + + // parent_detail_id 변경 시 depth 재계산. + if (body.containsKey("parent_detail_id")) { + Long newParent = toLong(body.get("parent_detail_id")); + int newDepth = 2; + if (newParent != null) { + Map parentParams = new HashMap<>(); + parentParams.put("code_detail_id", newParent); + parentParams.put("company_code", companyCode); + Integer parentDepth = sqlSession.selectOne(NS + "getCodeDetailParentDepth", parentParams); + newDepth = (parentDepth != null ? parentDepth : 1) + 1; + } + params.put("reparent", true); + params.put("parent_detail_id", newParent); + params.put("depth", newDepth); + } + + int updated = sqlSession.update(NS + "updateCodeDetail", params); + if (updated == 0) return null; + + return getCodeDetailInfo(codeDetailId, companyCode); + } + + @Transactional + public void deleteCodeDetail(Long codeDetailId, String companyCode) { + Map params = new HashMap<>(); + params.put("code_detail_id", codeDetailId); + params.put("company_code", companyCode); + + int deleted = sqlSession.delete(NS + "deleteCodeDetail", params); + if (deleted == 0) throw new IllegalArgumentException("코드를 찾을 수 없습니다."); + } + + public Map checkCodeDetailDuplicate(String codeInfo, String codeValue, + Long excludeId, String companyCode) { + Map result = new LinkedHashMap<>(); + if (codeValue == null || codeValue.trim().isEmpty()) { + result.put("is_duplicate", false); + result.put("message", "값을 입력해주세요."); + return result; + } + + Map params = new HashMap<>(); + params.put("code_info", codeInfo); + params.put("code_value", codeValue.trim()); + params.put("exclude_id", excludeId); + params.put("company_code", companyCode); + + Integer countObj = sqlSession.selectOne(NS + "getCodeDetailDuplicateCnt", params); + boolean isDuplicate = countObj != null && countObj > 0; + + result.put("is_duplicate", isDuplicate); + result.put("message", isDuplicate ? "이미 사용 중인 값입니다." : "사용 가능한 값입니다."); + return result; + } + + public Map hasCodeDetailChildren(Long codeDetailId, String companyCode) { + Map params = new HashMap<>(); + params.put("code_detail_id", codeDetailId); + params.put("company_code", companyCode); + + Integer countObj = sqlSession.selectOne(NS + "getCodeDetailChildrenCnt", params); int count = countObj != null ? countObj : 0; Map result = new LinkedHashMap<>(); result.put("has_children", count > 0); + result.put("count", count); return result; } - // ══════════════════════════════════════════════════════════════ - // 코드 수정 - // ══════════════════════════════════════════════════════════════ - - @Transactional - public Map updateCommonCode(String categoryCode, String codeValue, - Map body, String companyCode, String userId) { - Map params = new HashMap<>(); - params.put("category_code", categoryCode); - params.put("code_value", codeValue); - params.put("company_code", companyCode); - params.put("updated_by", userId); - - if (body.containsKey("code_name")) params.put("code_name", body.get("code_name")); - if (body.containsKey("code_name_eng")) params.put("code_name_eng", body.get("code_name_eng")); - if (body.containsKey("description")) params.put("description", body.get("description")); - if (body.containsKey("sort_order")) params.put("sort_order", body.get("sort_order")); - if (body.containsKey("is_active")) params.put("is_active", toActiveStr(body.get("is_active"))); - - if (body.containsKey("parent_code_value")) { - Object newParent = body.get("parent_code_value"); - params.put("parent_code_value", newParent); - // parentCodeValue 변경 시 depth 재계산 - if (newParent != null && !newParent.toString().isEmpty()) { - Map parentParams = new HashMap<>(); - parentParams.put("category_code", categoryCode); - parentParams.put("code_value", newParent.toString()); - parentParams.put("company_code", companyCode); - Integer parentDepth = sqlSession.selectOne(NS + "getCommonCodeParentDepth", parentParams); - params.put("depth", (parentDepth != null ? parentDepth : 0) + 1); - } else { - params.put("depth", 1); - } - } else if (body.containsKey("depth")) { - params.put("depth", body.get("depth")); - } - - int updated = sqlSession.update(NS + "updateCommonCode", params); - if (updated == 0) return null; - - Map q = new HashMap<>(); - q.put("category_code", categoryCode); - q.put("code_value", codeValue); - q.put("company_code", companyCode); - Map raw = sqlSession.selectOne(NS + "getCommonCodeInfo", q); - return raw != null ? transformCode(raw) : null; - } - - // ══════════════════════════════════════════════════════════════ - // 코드 삭제 - // ══════════════════════════════════════════════════════════════ - - @Transactional - public void deleteCommonCode(String categoryCode, String codeValue, String companyCode) { - Map params = new HashMap<>(); - params.put("category_code", categoryCode); - params.put("code_value", codeValue); - params.put("company_code", companyCode); - int deleted = sqlSession.delete(NS + "deleteCommonCode", params); - if (deleted == 0) throw new IllegalArgumentException("코드를 찾을 수 없습니다."); - } - - // ══════════════════════════════════════════════════════════════ - // 코드 옵션 목록 - // ══════════════════════════════════════════════════════════════ - - public List> getCommonCodeOptionList(String categoryCode, Map params) { - params.put("category_code", categoryCode); - - Object isActiveRaw = params.get("is_active"); - // 미지정 시 활성 코드만 반환 (드롭다운 기본 동작) - params.put("is_active", isActiveRaw != null ? toActiveStr(isActiveRaw) : "Y"); - - List> rawList = sqlSession.selectList(NS + "getCommonCodeOptionList", params); - List> options = new ArrayList<>(); - for (Map raw : rawList) { - Map opt = new LinkedHashMap<>(); - opt.put("value", raw.get("code_value")); - opt.put("label", raw.get("code_name")); - opt.put("label_eng", raw.get("code_name_eng")); - options.add(opt); - } - return options; - } - // ══════════════════════════════════════════════════════════════ // Private helpers // ══════════════════════════════════════════════════════════════ - /** snake_case 원본 + camelCase 별칭을 모두 포함하는 Map 반환 */ - private Map transformCode(Map raw) { - Map item = new LinkedHashMap<>(raw); - item.put("code_value", raw.get("code_value")); - item.put("code_name", raw.get("code_name")); - item.put("code_name_eng", raw.get("code_name_eng")); - item.put("code_category", raw.get("code_category")); - item.put("sort_order", raw.get("sort_order")); - item.put("is_active", raw.get("is_active")); - item.put("menu_objid", raw.get("menu_objid")); - item.put("company_code", raw.get("company_code")); - item.put("parent_code_value", raw.get("parent_code_value")); - item.put("created_by", raw.get("created_by")); - item.put("updated_by", raw.get("updated_by")); - item.put("created_date", raw.get("created_date")); - item.put("updated_date", raw.get("updated_date")); - return item; - } - - /** 평탄 목록을 부모-자식 트리로 변환 */ - @SuppressWarnings("unchecked") - private List> buildTree(List> codes) { - Map> byValue = new LinkedHashMap<>(); - for (Map code : codes) { - String val = objToStr(code.get("code_value")); - Map node = new LinkedHashMap<>(transformCode(code)); - node.put("children", new ArrayList>()); - byValue.put(val, node); - } - - List> roots = new ArrayList<>(); - for (Map code : codes) { - String val = objToStr(code.get("code_value")); - Object parentRaw = code.get("parent_code_value"); - String parentVal = (parentRaw != null) ? parentRaw.toString() : null; - - Map node = byValue.get(val); - if (parentVal == null || parentVal.isEmpty() || !byValue.containsKey(parentVal)) { - roots.add(node); - } else { - ((List>) byValue.get(parentVal).get("children")).add(node); - } - } - return roots; - } - - /** boolean/String → VARCHAR 'Y'/'N' 변환 */ + /** boolean / String / Number → VARCHAR(1) 'Y'/'N'. */ private String toActiveStr(Object val) { if (val == null) return "Y"; if (val instanceof Boolean b) return b ? "Y" : "N"; + if (val instanceof Number n) return n.intValue() != 0 ? "Y" : "N"; String s = val.toString().toLowerCase(); return ("true".equals(s) || "y".equals(s) || "1".equals(s)) ? "Y" : "N"; } @@ -463,7 +311,12 @@ public class CommonCodeService extends BaseService { catch (NumberFormatException e) { return defaultVal; } } - private String objToStr(Object val) { - return val != null ? val.toString() : ""; + private Long toLong(Object val) { + if (val == null) return null; + if (val instanceof Number n) return n.longValue(); + String s = val.toString().trim(); + if (s.isEmpty() || "null".equalsIgnoreCase(s)) return null; + try { return Long.parseLong(s); } + catch (NumberFormatException e) { return null; } } } diff --git a/backend-spring/src/main/java/com/erp/service/EntityReferenceService.java b/backend-spring/src/main/java/com/erp/service/EntityReferenceService.java index 337f137d..77f80627 100644 --- a/backend-spring/src/main/java/com/erp/service/EntityReferenceService.java +++ b/backend-spring/src/main/java/com/erp/service/EntityReferenceService.java @@ -101,20 +101,20 @@ public class EntityReferenceService extends BaseService { } public Map getCodeData(Map params) { - String codeCategory = (String) params.get("code_category"); + String codeInfo = (String) params.get("code_info"); String companyCode = (String) params.get("company_code"); int limit = toInt(params.getOrDefault("limit", 100)); Object search = params.get("search"); Map queryParams = new HashMap<>(); - queryParams.put("code_category", codeCategory); + queryParams.put("code_info", codeInfo); queryParams.put("company_code", companyCode); queryParams.put("limit", limit); if (search != null && !search.toString().isBlank()) { queryParams.put("search_like", "%" + search + "%"); } - log.info("공통 코드 데이터 조회: category={}, company={}", codeCategory, companyCode); + log.info("공통 코드 데이터 조회: category={}, company={}", codeInfo, companyCode); List> rows = sqlSession.selectList(NS + "selectCodeData", queryParams); @@ -128,7 +128,7 @@ public class EntityReferenceService extends BaseService { Map result = new LinkedHashMap<>(); result.put("options", options); - result.put("code_category", codeCategory); + result.put("code_info", codeInfo); return result; } diff --git a/backend-spring/src/main/java/com/erp/service/EntitySearchService.java b/backend-spring/src/main/java/com/erp/service/EntitySearchService.java index e6c328ad..5f46a180 100644 --- a/backend-spring/src/main/java/com/erp/service/EntitySearchService.java +++ b/backend-spring/src/main/java/com/erp/service/EntitySearchService.java @@ -394,12 +394,12 @@ public class EntitySearchService extends BaseService { Map ttcp = new HashMap<>(); ttcp.put("table_name", tableName); ttcp.put("column_name", columnName); - Map ttcRow = sqlSession.selectOne(NS + "getCodeCategoryInfo", ttcp); - String codeCategory = ttcRow != null ? (String) ttcRow.get("code_category") : null; + Map ttcRow = sqlSession.selectOne(NS + "getCodeInfoInfo", ttcp); + String codeInfo = ttcRow != null ? (String) ttcRow.get("code_info") : null; - if (codeCategory != null) { + if (codeInfo != null) { Map cip = new HashMap<>(); - cip.put("code_category", codeCategory); + cip.put("code_info", codeInfo); cip.put("raw_values", rawValues); cip.put("company_code", companyCode); List> ciRows = sqlSession.selectList(NS + "getCodeInfoList", cip); diff --git a/backend-spring/src/main/java/com/erp/service/ScreenManagementService.java b/backend-spring/src/main/java/com/erp/service/ScreenManagementService.java index 7426b016..2ae4db7c 100644 --- a/backend-spring/src/main/java/com/erp/service/ScreenManagementService.java +++ b/backend-spring/src/main/java/com/erp/service/ScreenManagementService.java @@ -994,7 +994,7 @@ public class ScreenManagementService extends BaseService { } @Transactional - public int copyCodeCategoryAndCodes(Map body) { + public int copyCodeInfoAndCodes(Map body) { String sourceCompanyCode = (String) body.get("source_company_code"); String targetCompanyCode = (String) body.get("target_company_code"); String userId = (String) body.get("user_id"); @@ -1002,16 +1002,16 @@ public class ScreenManagementService extends BaseService { Map params = new HashMap<>(); params.put("source_company_code", sourceCompanyCode); - List> categories = sqlSession.selectList(NS + "selectCodeCategoryForCopy", params); + List> categories = sqlSession.selectList(NS + "selectCodeInfoForCopy", params); int count = 0; for (Map cat : categories) { Map cp = new HashMap<>(cat); cp.put("target_company_code", targetCompanyCode); - sqlSession.insert(NS + "upsertCodeCategory", cp); + sqlSession.insert(NS + "upsertCodeInfo", cp); Map codeParams = new HashMap<>(); codeParams.put("source_company_code", sourceCompanyCode); - codeParams.put("code_category", cat.get("category_code")); + codeParams.put("code_info", cat.get("category_code")); List> codes = sqlSession.selectList(NS + "selectCodeInfoForCopy", codeParams); for (Map code : codes) { Map cop = new HashMap<>(code); diff --git a/backend-spring/src/main/java/com/erp/service/TableCategoryValueService.java b/backend-spring/src/main/java/com/erp/service/TableCategoryValueService.java deleted file mode 100644 index d5d0dc99..00000000 --- a/backend-spring/src/main/java/com/erp/service/TableCategoryValueService.java +++ /dev/null @@ -1,368 +0,0 @@ -package com.erp.service; - -import com.erp.common.BaseService; -import lombok.extern.slf4j.Slf4j; -import org.springframework.stereotype.Service; -import org.springframework.transaction.annotation.Transactional; - -import java.util.*; -import java.util.stream.Collectors; - -@Service -@Slf4j -public class TableCategoryValueService extends BaseService { - - private static final String NS = "tableCategoryValue."; - - // ══════════════════════════════════════════════════════════════ - // Category Columns - // ══════════════════════════════════════════════════════════════ - - public List> getCategoryColumns(Map params) { - log.info("카테고리 컬럼 목록 조회: tableName={}, companyCode={}", - params.get("table_name"), params.get("company_code")); - return sqlSession.selectList(NS + "getCategoryColumnList", params); - } - - public List> getAllCategoryColumns(Map params) { - log.info("전체 카테고리 컬럼 목록 조회: companyCode={}", params.get("company_code")); - return sqlSession.selectList(NS + "getAllCategoryColumnList", params); - } - - // ══════════════════════════════════════════════════════════════ - // Category Values — Read - // ══════════════════════════════════════════════════════════════ - - public List> getCategoryValues(Map params) { - log.info("카테고리 값 목록 조회: tableName={}, columnName={}, companyCode={}", - params.get("table_name"), params.get("column_name"), params.get("company_code")); - - List> flatList = sqlSession.selectList(NS + "getCategoryValueList", params); - List> hierarchy = buildHierarchy(flatList, null); - - log.info("카테고리 값 {}개 조회 완료 (평면)", flatList.size()); - return hierarchy; - } - - // ══════════════════════════════════════════════════════════════ - // Category Values — Write - // ══════════════════════════════════════════════════════════════ - - @Transactional - public Map addCategoryValue(Map params) { - String tableName = (String) params.get("table_name"); - String columnName = (String) params.get("column_name"); - String valueCode = (String) params.get("value_code"); - String valueLabel = (String) params.get("value_label"); - String companyCode = (String) params.get("company_code"); - - log.info("카테고리 값 추가: tableName={}, columnName={}, valueCode={}, companyCode={}", - tableName, columnName, valueCode, companyCode); - - Integer codeDup = sqlSession.selectOne(NS + "countDuplicateCode", params); - if (codeDup != null && codeDup > 0) { - throw new IllegalArgumentException("이미 존재하는 코드입니다"); - } - - Integer labelDup = sqlSession.selectOne(NS + "countDuplicateLabel", params); - if (labelDup != null && labelDup > 0) { - throw new IllegalArgumentException( - "이미 동일한 이름의 카테고리 값이 존재합니다: \"" + valueLabel + "\""); - } - - if (params.get("value_order") == null) params.put("value_order", 0); - if (params.get("depth") == null) params.put("depth", 1); - if (params.get("is_active") == null) params.put("is_active", true); - if (params.get("is_default") == null) params.put("is_default", false); - - sqlSession.insert(NS + "insertCategoryValue", params); - long valueId = toLong(params.get("value_id")); - - log.info("카테고리 값 추가 완료: valueId={}", valueId); - - Map fetchP = new HashMap<>(); - fetchP.put("value_id", valueId); - return sqlSession.selectOne(NS + "getCategoryValueInfo", fetchP); - } - - @Transactional - public Map updateCategoryValue(Map params) { - long valueId = toLong(params.get("value_id")); - String companyCode = (String) params.get("company_code"); - - log.info("카테고리 값 수정: valueId={}, companyCode={}", valueId, companyCode); - - if (params.get("value_label") != null) { - Map current = sqlSession.selectOne(NS + "getCategoryValueLabelInfo", - Map.of("value_id", valueId)); - if (current != null) { - Map labelP = new HashMap<>(); - labelP.put("table_name", current.get("table_name")); - labelP.put("column_name", current.get("column_name")); - labelP.put("company_code", current.get("company_code")); - labelP.put("value_label", params.get("value_label")); - labelP.put("value_id", valueId); - Integer dup = sqlSession.selectOne(NS + "countDuplicateLabelExcludeSelf", labelP); - if (dup != null && dup > 0) { - throw new IllegalArgumentException( - "이미 동일한 이름의 카테고리 값이 존재합니다: \"" - + params.get("value_label") + "\""); - } - } - } - - params.put("value_id", valueId); - Integer rows = sqlSession.selectOne(NS + "updateCategoryValue", params); - if (rows == null || rows == 0) { - // update returns affected rows via selectOne workaround; use update method instead - sqlSession.update(NS + "updateCategoryValue", params); - } - - Map fetchP = new HashMap<>(); - fetchP.put("value_id", valueId); - return sqlSession.selectOne(NS + "getCategoryValueInfo", fetchP); - } - - // ══════════════════════════════════════════════════════════════ - // Category Values — Delete - // ══════════════════════════════════════════════════════════════ - - @Transactional - public void deleteCategoryValue(Map params) { - long valueId = toLong(params.get("value_id")); - String companyCode = (String) params.get("company_code"); - - log.info("카테고리 값 삭제: valueId={}, companyCode={}", valueId, companyCode); - - List> childRows = sqlSession.selectList(NS + "getChildValueIdList", params); - List allIds = new ArrayList<>(); - allIds.add(valueId); - childRows.forEach(r -> allIds.add(toLong(r.get("value_id")))); - - log.info("삭제 대상 카테고리 값 수집 완료: 자신={}, 하위={}", valueId, childRows.size()); - - for (Long id : allIds) { - checkNotInUse(id, companyCode); - } - - List reversed = new ArrayList<>(allIds); - Collections.reverse(reversed); - for (Long id : reversed) { - Map delP = new HashMap<>(); - delP.put("value_id", id); - delP.put("company_code", companyCode); - sqlSession.delete(NS + "deleteValueById", delP); - } - - log.info("카테고리 값 삭제 완료: totalDeleted={}", allIds.size()); - } - - @Transactional - public void bulkDeleteCategoryValues(Map params) { - log.info("카테고리 값 일괄 삭제: count={}, companyCode={}", - ((List) params.get("value_ids")).size(), params.get("company_code")); - sqlSession.update(NS + "bulkSoftDeleteValues", params); - } - - @Transactional - public void reorderCategoryValues(Map params) { - List rawIds = (List) params.get("ordered_value_ids"); - String companyCode = (String) params.get("company_code"); - - log.info("카테고리 값 순서 변경: count={}, companyCode={}", rawIds.size(), companyCode); - - for (int i = 0; i < rawIds.size(); i++) { - Map p = new HashMap<>(); - p.put("value_id", toLong(rawIds.get(i))); - p.put("value_order", i + 1); - p.put("company_code", companyCode); - sqlSession.update(NS + "updateValueOrder", p); - } - } - - // ══════════════════════════════════════════════════════════════ - // Column Mapping - // ══════════════════════════════════════════════════════════════ - - public Map getColumnMapping(Map params) { - log.info("컬럼 매핑 조회: tableName={}, menuObjid={}, companyCode={}", - params.get("table_name"), params.get("menu_objid"), params.get("company_code")); - - List> rows = sqlSession.selectList(NS + "getColumnMappingList", params); - - Map mapping = new LinkedHashMap<>(); - for (Map row : rows) { - mapping.put(String.valueOf(row.get("logical_column_name")), - String.valueOf(row.get("physical_column_name"))); - } - log.info("컬럼 매핑 {}개 조회 완료", mapping.size()); - return mapping; - } - - @Transactional - public Map createColumnMapping(Map params) { - String tableName = (String) params.get("table_name"); - String logicalColumnName = (String) params.get("logical_column_name"); - String physicalColumnName = (String) params.get("physical_column_name"); - - log.info("컬럼 매핑 생성: tableName={}, logical={}, physical={}, companyCode={}", - tableName, logicalColumnName, physicalColumnName, params.get("company_code")); - - Integer colExists = sqlSession.selectOne(NS + "checkPhysicalColumnExists", params); - if (colExists == null || colExists == 0) { - throw new IllegalArgumentException( - "테이블 " + tableName + "에 컬럼 " + physicalColumnName + "이(가) 존재하지 않습니다"); - } - - sqlSession.insert(NS + "upsertColumnMapping", params); - Map result = sqlSession.selectOne(NS + "getColumnMappingInfo", params); - - log.info("컬럼 매핑 생성 완료: mappingId={}", result != null ? result.get("mapping_id") : "?"); - return result; - } - - public List> getLogicalColumns(Map params) { - log.info("논리적 컬럼 목록 조회: tableName={}, menuObjid={}, companyCode={}", - params.get("table_name"), params.get("menu_objid"), params.get("company_code")); - return sqlSession.selectList(NS + "getLogicalColumnList", params); - } - - @Transactional - public void deleteColumnMapping(Map params) { - int deleted = sqlSession.delete(NS + "deleteColumnMappingById", params); - if (deleted == 0) { - throw new IllegalArgumentException("컬럼 매핑을 찾을 수 없거나 권한이 없습니다"); - } - log.info("컬럼 매핑 삭제 완료: mappingId={}", params.get("mapping_id")); - } - - @Transactional - public int deleteColumnMappingsByColumn(Map params) { - int deleted = sqlSession.delete(NS + "deleteColumnMappingsByColumn", params); - log.info("테이블+컬럼 기준 매핑 삭제 완료: tableName={}, columnName={}, deletedCount={}", - params.get("table_name"), params.get("column_name"), deleted); - return deleted; - } - - // ══════════════════════════════════════════════════════════════ - // Labels by Codes - // ══════════════════════════════════════════════════════════════ - - public Map getCategoryLabelsByCodes(Map params) { - Object rawCodes = params.get("value_codes"); - if (!(rawCodes instanceof List) || ((List) rawCodes).isEmpty()) { - return new LinkedHashMap<>(); - } - - log.info("카테고리 코드로 라벨 조회: count={}, companyCode={}", - ((List) rawCodes).size(), params.get("company_code")); - - List> rows = sqlSession.selectList(NS + "getLabelListByCodes", params); - - Map labels = new LinkedHashMap<>(); - for (Map row : rows) { - String code = String.valueOf(row.get("value_code")); - if (!labels.containsKey(code)) { - labels.put(code, row.get("value_label")); - } - } - log.info("카테고리 라벨 {}개 조회 완료", labels.size()); - return labels; - } - - // ══════════════════════════════════════════════════════════════ - // Second-Level Menus - // ══════════════════════════════════════════════════════════════ - - public List> getSecondLevelMenus(Map params) { - log.info("2레벨 메뉴 목록 조회: companyCode={}", params.get("company_code")); - - Integer hasCC = sqlSession.selectOne(NS + "checkMenuInfoHasCompanyCode", null); - params.put("has_company_code", hasCC != null && hasCC > 0); - log.info("menu_info.company_code 컬럼 존재 여부: {}", hasCC != null && hasCC > 0); - - List> menus = sqlSession.selectList(NS + "getSecondLevelMenuList", params); - log.info("2레벨 메뉴 {}개 조회 완료", menus.size()); - return menus; - } - - // ══════════════════════════════════════════════════════════════ - // private helpers - // ══════════════════════════════════════════════════════════════ - - private void checkNotInUse(long valueId, String companyCode) { - Map p = new HashMap<>(); - p.put("value_id", valueId); - p.put("company_code", companyCode); - - Map valueInfo = sqlSession.selectOne(NS + "getCategoryValueUsageInfo", p); - if (valueInfo == null) { - throw new IllegalArgumentException("카테고리 값을 찾을 수 없습니다"); - } - - String tableName = String.valueOf(valueInfo.get("table_name")); - String columnName = String.valueOf(valueInfo.get("column_name")); - String valueCode = String.valueOf(valueInfo.get("value_code")); - String valueLabel = String.valueOf(valueInfo.get("value_label")); - - String safeTable = sanitize(tableName); - String safeColumn = sanitize(columnName); - - if (safeTable.isEmpty() || safeColumn.isEmpty()) return; - - Integer tableExists = sqlSession.selectOne(NS + "checkTableExistsForUsage", - Map.of("table_name", safeTable)); - if (tableExists == null || tableExists == 0) return; - - Map countP = new HashMap<>(); - countP.put("safe_table_name", safeTable); - countP.put("safe_column_name", safeColumn); - countP.put("value_code", valueCode); - countP.put("company_code", companyCode); - Integer count = sqlSession.selectOne(NS + "countValueUsageInTable", countP); - - if (count != null && count > 0) { - List> menus = sqlSession.selectList(NS + "getMenuListUsingTable", - Map.of("table_name", tableName, "company_code", companyCode)); - - StringBuilder msg = new StringBuilder(); - msg.append("카테고리 \"").append(valueLabel).append("\"을(를) 삭제할 수 없습니다.\n"); - msg.append("\n현재 ").append(count).append("개의 데이터에서 사용 중입니다."); - - if (!menus.isEmpty()) { - String menuNames = menus.stream() - .map(m -> String.valueOf(m.get("menu_name"))) - .collect(Collectors.joining(", ")); - msg.append("\n\n다음 메뉴에서 사용 중입니다:\n").append(menuNames); - } - msg.append("\n\n메뉴에서 사용하는 카테고리 항목을 수정한 후 다시 삭제해주세요."); - - throw new IllegalArgumentException(msg.toString()); - } - } - - private List> buildHierarchy( - List> values, Object parentId) { - List> result = new ArrayList<>(); - for (Map v : values) { - Object pid = v.get("parent_value_id"); - if (Objects.equals(pid, parentId)) { - List> children = buildHierarchy(values, v.get("value_id")); - v.put("children", children); - result.add(v); - } - } - return result; - } - - private String sanitize(String name) { - if (name == null) return ""; - return name.replaceAll("[^a-zA-Z0-9_]", ""); - } - - private long toLong(Object val) { - if (val == null) return 0L; - if (val instanceof Number) return ((Number) val).longValue(); - try { return Long.parseLong(val.toString()); } catch (NumberFormatException e) { return 0L; } - } -} diff --git a/backend-spring/src/main/java/com/erp/service/TableManagementService.java b/backend-spring/src/main/java/com/erp/service/TableManagementService.java index 8733a6c9..22067b6e 100644 --- a/backend-spring/src/main/java/com/erp/service/TableManagementService.java +++ b/backend-spring/src/main/java/com/erp/service/TableManagementService.java @@ -169,7 +169,7 @@ public class TableManagementService extends BaseService { params.put("column_label", settings.get("column_label")); params.put("input_type", inputType); params.put("detail_settings", toJsonString(settings.get("detail_settings"))); - params.put("code_category", "code".equals(inputType) ? settings.get("code_category") : null); + params.put("code_info", "code".equals(inputType) ? settings.get("code_info") : null); params.put("code_value", "code".equals(inputType) ? settings.get("code_value") : null); params.put("reference_table", "entity".equals(inputType) ? settings.get("reference_table") : null); params.put("reference_column", "entity".equals(inputType) ? settings.get("reference_column") : null); diff --git a/backend-spring/src/main/resources/mapper/cascadingAutoFill.xml b/backend-spring/src/main/resources/mapper/cascadingAutoFill.xml deleted file mode 100644 index 1b63e267..00000000 --- a/backend-spring/src/main/resources/mapper/cascadingAutoFill.xml +++ /dev/null @@ -1,128 +0,0 @@ - - - - - - - AND (G.GROUP_NAME ILIKE '%' || #{keyword} || '%') - - - AND G.IS_ACTIVE = #{is_active} - - - - - - - - - - - - - - - INSERT INTO CASCADING_AUTO_FILL_GROUP ( - GROUP_CODE, GROUP_NAME, DESCRIPTION, - MASTER_TABLE, MASTER_VALUE_COLUMN, MASTER_LABEL_COLUMN, - COMPANY_CODE, IS_ACTIVE, CREATED_DATE - ) VALUES ( - #{group_code}, - #{group_name}, - #{description, jdbcType=VARCHAR}, - #{master_table}, - #{master_value_column}, - #{master_label_column, jdbcType=VARCHAR}, - #{company_code}, - #{is_active, jdbcType=VARCHAR}, - CURRENT_TIMESTAMP - ) - - - - INSERT INTO CASCADING_AUTO_FILL_MAPPING ( - GROUP_CODE, COMPANY_CODE, SOURCE_COLUMN, TARGET_FIELD, TARGET_LABEL, - IS_EDITABLE, IS_REQUIRED, DEFAULT_VALUE, SORT_ORDER - ) VALUES ( - #{group_code}, - #{company_code}, - #{source_column}, - #{target_field}, - #{target_label, jdbcType=VARCHAR}, - #{is_editable, jdbcType=VARCHAR}, - #{is_required, jdbcType=VARCHAR}, - #{default_value, jdbcType=VARCHAR}, - #{sort_order} - ) - - - - UPDATE CASCADING_AUTO_FILL_GROUP SET - GROUP_NAME = COALESCE(#{group_name, jdbcType=VARCHAR}, GROUP_NAME), - DESCRIPTION = COALESCE(#{description, jdbcType=VARCHAR}, DESCRIPTION), - MASTER_TABLE = COALESCE(#{master_table, jdbcType=VARCHAR}, MASTER_TABLE), - MASTER_VALUE_COLUMN = COALESCE(#{master_value_column, jdbcType=VARCHAR}, MASTER_VALUE_COLUMN), - MASTER_LABEL_COLUMN = COALESCE(#{master_label_column, jdbcType=VARCHAR}, MASTER_LABEL_COLUMN), - IS_ACTIVE = COALESCE(#{is_active, jdbcType=VARCHAR}, IS_ACTIVE), - UPDATED_DATE = CURRENT_TIMESTAMP - WHERE GROUP_CODE = #{group_code} - AND (COMPANY_CODE = #{company_code} OR COMPANY_CODE = '*') - - - - DELETE FROM CASCADING_AUTO_FILL_MAPPING - WHERE GROUP_CODE = #{group_code} - AND (COMPANY_CODE = #{company_code} OR COMPANY_CODE = '*') - - - - DELETE FROM CASCADING_AUTO_FILL_GROUP - WHERE GROUP_CODE = #{group_code} - - AND (COMPANY_CODE = #{company_code} OR COMPANY_CODE = '*') - - - - diff --git a/backend-spring/src/main/resources/mapper/cascadingCondition.xml b/backend-spring/src/main/resources/mapper/cascadingCondition.xml deleted file mode 100644 index ae0515f8..00000000 --- a/backend-spring/src/main/resources/mapper/cascadingCondition.xml +++ /dev/null @@ -1,100 +0,0 @@ - - - - - - - AND CONDITION_NAME ILIKE '%' || #{keyword} || '%' - - - AND IS_ACTIVE = #{is_active} - - - AND RELATION_CODE = #{relation_code} - - - AND RELATION_TYPE = #{relation_type} - - - - - - - - - - - INSERT INTO CASCADING_CONDITION ( - RELATION_TYPE, RELATION_CODE, CONDITION_NAME, - CONDITION_FIELD, CONDITION_OPERATOR, CONDITION_VALUE, - FILTER_COLUMN, FILTER_VALUES, PRIORITY, - COMPANY_CODE, IS_ACTIVE, CREATED_DATE - ) VALUES ( - COALESCE(#{relation_type}, 'RELATION'), #{relation_code}, #{condition_name}, - #{condition_field}, COALESCE(#{condition_operator}, 'EQ'), #{condition_value}, - #{filter_column}, #{filter_values}, COALESCE(#{priority}, 0), - #{company_code}, COALESCE(#{is_active}, 'Y'), CURRENT_TIMESTAMP - ) - - - - UPDATE CASCADING_CONDITION SET - CONDITION_NAME = COALESCE(#{condition_name}, CONDITION_NAME), - CONDITION_FIELD = COALESCE(#{condition_field}, CONDITION_FIELD), - CONDITION_OPERATOR = COALESCE(#{condition_operator}, CONDITION_OPERATOR), - CONDITION_VALUE = COALESCE(#{condition_value}, CONDITION_VALUE), - FILTER_COLUMN = COALESCE(#{filter_column}, FILTER_COLUMN), - FILTER_VALUES = COALESCE(#{filter_values}, FILTER_VALUES), - PRIORITY = COALESCE(#{priority}, PRIORITY), - IS_ACTIVE = COALESCE(#{is_active}, IS_ACTIVE), - UPDATED_DATE = CURRENT_TIMESTAMP - WHERE CONDITION_ID = #{condition_id} - - - - - DELETE FROM CASCADING_CONDITION - WHERE CONDITION_ID = #{condition_id} - - - - - - diff --git a/backend-spring/src/main/resources/mapper/cascadingHierarchy.xml b/backend-spring/src/main/resources/mapper/cascadingHierarchy.xml deleted file mode 100644 index e5e83783..00000000 --- a/backend-spring/src/main/resources/mapper/cascadingHierarchy.xml +++ /dev/null @@ -1,219 +0,0 @@ - - - - - - - AND (G.GROUP_NAME ILIKE '%' || #{keyword} || '%') - - - AND G.IS_ACTIVE = #{is_active} - - - AND G.HIERARCHY_TYPE = #{hierarchy_type} - - - - - - - - - - - - - - - - - - - INSERT INTO CASCADING_HIERARCHY_GROUP ( - GROUP_CODE, GROUP_NAME, DESCRIPTION, HIERARCHY_TYPE, - MAX_LEVELS, IS_FIXED_LEVELS, - SELF_REF_TABLE, SELF_REF_ID_COLUMN, SELF_REF_PARENT_COLUMN, - SELF_REF_VALUE_COLUMN, SELF_REF_LABEL_COLUMN, SELF_REF_LEVEL_COLUMN, SELF_REF_ORDER_COLUMN, - BOM_TABLE, BOM_PARENT_COLUMN, BOM_CHILD_COLUMN, - BOM_ITEM_TABLE, BOM_ITEM_ID_COLUMN, BOM_ITEM_LABEL_COLUMN, BOM_QTY_COLUMN, BOM_LEVEL_COLUMN, - EMPTY_MESSAGE, NO_OPTIONS_MESSAGE, LOADING_MESSAGE, - COMPANY_CODE, IS_ACTIVE, CREATED_BY, CREATED_DATE - ) VALUES ( - #{group_code}, - #{group_name}, - #{description, jdbcType=VARCHAR}, - #{hierarchy_type}, - #{max_levels, jdbcType=INTEGER}, - #{is_fixed_levels, jdbcType=VARCHAR}, - #{self_ref_table, jdbcType=VARCHAR}, - #{self_ref_id_column, jdbcType=VARCHAR}, - #{self_ref_parent_column, jdbcType=VARCHAR}, - #{self_ref_value_column, jdbcType=VARCHAR}, - #{self_ref_label_column, jdbcType=VARCHAR}, - #{self_ref_level_column, jdbcType=VARCHAR}, - #{self_ref_order_column, jdbcType=VARCHAR}, - #{bom_table, jdbcType=VARCHAR}, - #{bom_parent_column, jdbcType=VARCHAR}, - #{bom_child_column, jdbcType=VARCHAR}, - #{bom_item_table, jdbcType=VARCHAR}, - #{bom_item_id_column, jdbcType=VARCHAR}, - #{bom_item_label_column, jdbcType=VARCHAR}, - #{bom_qty_column, jdbcType=VARCHAR}, - #{bom_level_column, jdbcType=VARCHAR}, - #{empty_message, jdbcType=VARCHAR}, - #{no_options_message, jdbcType=VARCHAR}, - #{loading_message, jdbcType=VARCHAR}, - #{company_code}, - 'Y', - #{created_by, jdbcType=VARCHAR}, - CURRENT_TIMESTAMP - ) - - - - INSERT INTO CASCADING_HIERARCHY_LEVEL ( - GROUP_CODE, COMPANY_CODE, LEVEL_ORDER, LEVEL_NAME, LEVEL_CODE, - TABLE_NAME, VALUE_COLUMN, LABEL_COLUMN, PARENT_KEY_COLUMN, - FILTER_COLUMN, FILTER_VALUE, ORDER_COLUMN, ORDER_DIRECTION, - PLACEHOLDER, IS_REQUIRED, IS_SEARCHABLE, IS_ACTIVE, CREATED_DATE - ) VALUES ( - #{group_code}, - #{company_code}, - #{level_order}, - #{level_name}, - #{level_code, jdbcType=VARCHAR}, - #{table_name}, - #{value_column}, - #{label_column}, - #{parent_key_column, jdbcType=VARCHAR}, - #{filter_column, jdbcType=VARCHAR}, - #{filter_value, jdbcType=VARCHAR}, - #{order_column, jdbcType=VARCHAR}, - #{order_direction, jdbcType=VARCHAR}, - #{placeholder, jdbcType=VARCHAR}, - #{is_required, jdbcType=VARCHAR}, - #{is_searchable, jdbcType=VARCHAR}, - 'Y', - CURRENT_TIMESTAMP - ) - - - - UPDATE CASCADING_HIERARCHY_GROUP SET - GROUP_NAME = COALESCE(#{group_name, jdbcType=VARCHAR}, GROUP_NAME), - DESCRIPTION = COALESCE(#{description, jdbcType=VARCHAR}, DESCRIPTION), - MAX_LEVELS = COALESCE(#{max_levels, jdbcType=INTEGER}, MAX_LEVELS), - IS_FIXED_LEVELS = COALESCE(#{is_fixed_levels, jdbcType=VARCHAR}, IS_FIXED_LEVELS), - EMPTY_MESSAGE = COALESCE(#{empty_message, jdbcType=VARCHAR}, EMPTY_MESSAGE), - NO_OPTIONS_MESSAGE = COALESCE(#{no_options_message, jdbcType=VARCHAR}, NO_OPTIONS_MESSAGE), - LOADING_MESSAGE = COALESCE(#{loading_message, jdbcType=VARCHAR}, LOADING_MESSAGE), - IS_ACTIVE = COALESCE(#{is_active, jdbcType=VARCHAR}, IS_ACTIVE), - UPDATED_BY = #{updated_by, jdbcType=VARCHAR}, - UPDATED_DATE = CURRENT_TIMESTAMP - WHERE GROUP_CODE = #{group_code} - AND (COMPANY_CODE = #{company_code} OR COMPANY_CODE = '*') - - - - UPDATE CASCADING_HIERARCHY_LEVEL SET - LEVEL_NAME = COALESCE(#{level_name, jdbcType=VARCHAR}, LEVEL_NAME), - TABLE_NAME = COALESCE(#{table_name, jdbcType=VARCHAR}, TABLE_NAME), - VALUE_COLUMN = COALESCE(#{value_column, jdbcType=VARCHAR}, VALUE_COLUMN), - LABEL_COLUMN = COALESCE(#{label_column, jdbcType=VARCHAR}, LABEL_COLUMN), - PARENT_KEY_COLUMN = COALESCE(#{parent_key_column, jdbcType=VARCHAR}, PARENT_KEY_COLUMN), - FILTER_COLUMN = COALESCE(#{filter_column, jdbcType=VARCHAR}, FILTER_COLUMN), - FILTER_VALUE = COALESCE(#{filter_value, jdbcType=VARCHAR}, FILTER_VALUE), - ORDER_COLUMN = COALESCE(#{order_column, jdbcType=VARCHAR}, ORDER_COLUMN), - ORDER_DIRECTION = COALESCE(#{order_direction, jdbcType=VARCHAR}, ORDER_DIRECTION), - PLACEHOLDER = COALESCE(#{placeholder, jdbcType=VARCHAR}, PLACEHOLDER), - IS_REQUIRED = COALESCE(#{is_required, jdbcType=VARCHAR}, IS_REQUIRED), - IS_SEARCHABLE = COALESCE(#{is_searchable, jdbcType=VARCHAR}, IS_SEARCHABLE), - IS_ACTIVE = COALESCE(#{is_active, jdbcType=VARCHAR}, IS_ACTIVE), - UPDATED_DATE = CURRENT_TIMESTAMP - WHERE LEVEL_ID = #{level_id} - - - - DELETE FROM CASCADING_HIERARCHY_LEVEL - WHERE GROUP_CODE = #{group_code} - - AND (COMPANY_CODE = #{company_code} OR COMPANY_CODE = '*') - - - - - DELETE FROM CASCADING_HIERARCHY_LEVEL - WHERE LEVEL_ID = #{level_id} - - AND (COMPANY_CODE = #{company_code} OR COMPANY_CODE = '*') - - - - - DELETE FROM CASCADING_HIERARCHY_GROUP - WHERE GROUP_CODE = #{group_code} - - AND (COMPANY_CODE = #{company_code} OR COMPANY_CODE = '*') - - - - diff --git a/backend-spring/src/main/resources/mapper/cascadingMutualExclusion.xml b/backend-spring/src/main/resources/mapper/cascadingMutualExclusion.xml deleted file mode 100644 index 246396db..00000000 --- a/backend-spring/src/main/resources/mapper/cascadingMutualExclusion.xml +++ /dev/null @@ -1,145 +0,0 @@ - - - - - - - AND IS_ACTIVE = #{is_active} - - - AND EXCLUSION_NAME ILIKE '%' || #{keyword} || '%' - - - - - - - - - - - - - - - - - INSERT INTO CASCADING_MUTUAL_EXCLUSION ( - EXCLUSION_CODE - , EXCLUSION_NAME - , FIELD_NAMES - , SOURCE_TABLE - , VALUE_COLUMN - , LABEL_COLUMN - , EXCLUSION_TYPE - , ERROR_MESSAGE - , COMPANY_CODE - , IS_ACTIVE - , CREATED_DATE - ) VALUES ( - #{exclusion_code, jdbcType=VARCHAR} - , #{exclusion_name, jdbcType=VARCHAR} - , #{field_names, jdbcType=VARCHAR} - , #{source_table, jdbcType=VARCHAR} - , #{value_column, jdbcType=VARCHAR} - , #{label_column, jdbcType=VARCHAR} - , #{exclusion_type, jdbcType=VARCHAR} - , #{error_message, jdbcType=VARCHAR} - , #{company_code} - , 'Y' - , CURRENT_TIMESTAMP - ) - - - - UPDATE CASCADING_MUTUAL_EXCLUSION - SET - EXCLUSION_NAME = COALESCE(#{exclusion_name, jdbcType=VARCHAR}, EXCLUSION_NAME) - , FIELD_NAMES = COALESCE(#{field_names, jdbcType=VARCHAR}, FIELD_NAMES) - , SOURCE_TABLE = COALESCE(#{source_table, jdbcType=VARCHAR}, SOURCE_TABLE) - , VALUE_COLUMN = COALESCE(#{value_column, jdbcType=VARCHAR}, VALUE_COLUMN) - , LABEL_COLUMN = COALESCE(#{label_column, jdbcType=VARCHAR}, LABEL_COLUMN) - , EXCLUSION_TYPE = COALESCE(#{exclusion_type, jdbcType=VARCHAR}, EXCLUSION_TYPE) - , ERROR_MESSAGE = COALESCE(#{error_message, jdbcType=VARCHAR}, ERROR_MESSAGE) - , IS_ACTIVE = COALESCE(#{is_active, jdbcType=VARCHAR}, IS_ACTIVE) - WHERE EXCLUSION_ID = #{id} - - - - - - DELETE FROM CASCADING_MUTUAL_EXCLUSION - WHERE EXCLUSION_ID = #{id} - - - - diff --git a/backend-spring/src/main/resources/mapper/cascadingRelation.xml b/backend-spring/src/main/resources/mapper/cascadingRelation.xml deleted file mode 100644 index e6d186b4..00000000 --- a/backend-spring/src/main/resources/mapper/cascadingRelation.xml +++ /dev/null @@ -1,160 +0,0 @@ - - - - - - RELATION_ID - , RELATION_CODE - , RELATION_NAME - , DESCRIPTION - , PARENT_TABLE - , PARENT_VALUE_COLUMN - , PARENT_LABEL_COLUMN - , CHILD_TABLE - , CHILD_FILTER_COLUMN - , CHILD_VALUE_COLUMN - , CHILD_LABEL_COLUMN - , CHILD_ORDER_COLUMN - , CHILD_ORDER_DIRECTION - , EMPTY_PARENT_MESSAGE - , NO_OPTIONS_MESSAGE - , LOADING_MESSAGE - , CLEAR_ON_PARENT_CHANGE - , COMPANY_CODE - , IS_ACTIVE - , CREATED_BY - , CREATED_DATE - , UPDATED_BY - , UPDATED_DATE - - - - - AND IS_ACTIVE = #{is_active} - - - AND (RELATION_NAME ILIKE '%' || #{keyword} || '%' - OR RELATION_CODE ILIKE '%' || #{keyword} || '%') - - - - - - - - - - - - - - INSERT INTO CASCADING_RELATION ( - RELATION_CODE - , RELATION_NAME - , DESCRIPTION - , PARENT_TABLE - , PARENT_VALUE_COLUMN - , PARENT_LABEL_COLUMN - , CHILD_TABLE - , CHILD_FILTER_COLUMN - , CHILD_VALUE_COLUMN - , CHILD_LABEL_COLUMN - , CHILD_ORDER_COLUMN - , CHILD_ORDER_DIRECTION - , EMPTY_PARENT_MESSAGE - , NO_OPTIONS_MESSAGE - , LOADING_MESSAGE - , CLEAR_ON_PARENT_CHANGE - , COMPANY_CODE - , IS_ACTIVE - , CREATED_BY - , CREATED_DATE - ) VALUES ( - #{relation_code, jdbcType=VARCHAR} - , #{relation_name, jdbcType=VARCHAR} - , #{description, jdbcType=VARCHAR} - , #{parent_table, jdbcType=VARCHAR} - , #{parent_value_column, jdbcType=VARCHAR} - , #{parent_label_column, jdbcType=VARCHAR} - , #{child_table, jdbcType=VARCHAR} - , #{child_filter_column, jdbcType=VARCHAR} - , #{child_value_column, jdbcType=VARCHAR} - , #{child_label_column, jdbcType=VARCHAR} - , #{child_order_column, jdbcType=VARCHAR} - , #{child_order_direction, jdbcType=VARCHAR} - , #{empty_parent_message, jdbcType=VARCHAR} - , #{no_options_message, jdbcType=VARCHAR} - , #{loading_message, jdbcType=VARCHAR} - , #{clear_on_parent_change, jdbcType=VARCHAR} - , #{company_code} - , #{is_active, jdbcType=VARCHAR} - , #{user_id, jdbcType=VARCHAR} - , CURRENT_TIMESTAMP - ) - - - - UPDATE CASCADING_RELATION - SET - RELATION_NAME = COALESCE(#{relation_name, jdbcType=VARCHAR}, RELATION_NAME) - , DESCRIPTION = COALESCE(#{description, jdbcType=VARCHAR}, DESCRIPTION) - , PARENT_TABLE = COALESCE(#{parent_table, jdbcType=VARCHAR}, PARENT_TABLE) - , PARENT_VALUE_COLUMN = COALESCE(#{parent_value_column, jdbcType=VARCHAR}, PARENT_VALUE_COLUMN) - , PARENT_LABEL_COLUMN = COALESCE(#{parent_label_column, jdbcType=VARCHAR}, PARENT_LABEL_COLUMN) - , CHILD_TABLE = COALESCE(#{child_table, jdbcType=VARCHAR}, CHILD_TABLE) - , CHILD_FILTER_COLUMN = COALESCE(#{child_filter_column, jdbcType=VARCHAR}, CHILD_FILTER_COLUMN) - , CHILD_VALUE_COLUMN = COALESCE(#{child_value_column, jdbcType=VARCHAR}, CHILD_VALUE_COLUMN) - , CHILD_LABEL_COLUMN = COALESCE(#{child_label_column, jdbcType=VARCHAR}, CHILD_LABEL_COLUMN) - , CHILD_ORDER_COLUMN = COALESCE(#{child_order_column, jdbcType=VARCHAR}, CHILD_ORDER_COLUMN) - , CHILD_ORDER_DIRECTION = COALESCE(#{child_order_direction, jdbcType=VARCHAR}, CHILD_ORDER_DIRECTION) - , EMPTY_PARENT_MESSAGE = COALESCE(#{empty_parent_message, jdbcType=VARCHAR}, EMPTY_PARENT_MESSAGE) - , NO_OPTIONS_MESSAGE = COALESCE(#{no_options_message, jdbcType=VARCHAR}, NO_OPTIONS_MESSAGE) - , LOADING_MESSAGE = COALESCE(#{loading_message, jdbcType=VARCHAR}, LOADING_MESSAGE) - , CLEAR_ON_PARENT_CHANGE = COALESCE(#{clear_on_parent_change, jdbcType=VARCHAR}, CLEAR_ON_PARENT_CHANGE) - , IS_ACTIVE = COALESCE(#{is_active, jdbcType=VARCHAR}, IS_ACTIVE) - , UPDATED_BY = #{user_id, jdbcType=VARCHAR} - , UPDATED_DATE = CURRENT_TIMESTAMP - WHERE RELATION_ID = #{id} - - - - - - UPDATE CASCADING_RELATION - SET - IS_ACTIVE = 'N' - , UPDATED_BY = #{user_id, jdbcType=VARCHAR} - , UPDATED_DATE = CURRENT_TIMESTAMP - WHERE RELATION_ID = #{id} - - - - diff --git a/backend-spring/src/main/resources/mapper/categoryTree.xml b/backend-spring/src/main/resources/mapper/categoryTree.xml deleted file mode 100644 index 0aca88cb..00000000 --- a/backend-spring/src/main/resources/mapper/categoryTree.xml +++ /dev/null @@ -1,182 +0,0 @@ - - - - - - - value_id, table_name, column_name, value_code, value_label, value_order, - parent_value_id, depth, path, description, color, icon, - is_active, is_default, company_code, - CREATED_DATE, UPDATED_DATE, created_by, updated_by - - - - - - - - - - - INSERT INTO category_values ( - table_name, column_name, value_code, value_label, value_order, - parent_value_id, depth, path, description, color, icon, - is_active, is_default, company_code, created_by, updated_by - ) VALUES ( - #{table_name}, #{column_name}, #{value_code}, #{value_label}, #{value_order}, - #{parent_value_id}, #{depth}, #{path}, #{description}, #{color}, #{icon}, - #{is_active}, #{is_default}, #{company_code}, #{created_by}, #{created_by} - ) - - - - - UPDATE category_values - SET - value_code = COALESCE(#{value_code}, value_code), - value_label = COALESCE(#{value_label}, value_label), - value_order = COALESCE(#{value_order}, value_order), - parent_value_id = #{parent_value_id}, - depth = #{depth}, - path = #{path}, - description = COALESCE(#{description}, description), - color = COALESCE(#{color}, color), - icon = COALESCE(#{icon}, icon), - is_active = COALESCE(#{is_active}, is_active), - is_default = COALESCE(#{is_default}, is_default), - UPDATED_DATE = NOW(), - updated_by = #{updated_by} - - WHERE (company_code = #{company_code} OR company_code = '*') - AND value_id = #{value_id} - - - - - DELETE FROM category_values - - WHERE (company_code = #{company_code} OR company_code = '*') - AND value_id = #{value_id} - - - - - - - - - - - - - - - - - - - - - - - UPDATE category_values - SET path = #{path}, UPDATED_DATE = NOW() - - WHERE value_id = #{value_id} - - - - - - - - - diff --git a/backend-spring/src/main/resources/mapper/categoryValueCascading.xml b/backend-spring/src/main/resources/mapper/categoryValueCascading.xml deleted file mode 100644 index 0716c2b7..00000000 --- a/backend-spring/src/main/resources/mapper/categoryValueCascading.xml +++ /dev/null @@ -1,179 +0,0 @@ - - - - - - - AND (RELATION_NAME ILIKE '%' || #{keyword} || '%' OR RELATION_CODE ILIKE '%' || #{keyword} || '%') - - - AND IS_ACTIVE = #{is_active} - - - - - - - - - - - - - INSERT INTO CATEGORY_VALUE_CASCADING_GROUP ( - RELATION_CODE - , RELATION_NAME - , DESCRIPTION - , PARENT_TABLE_NAME - , PARENT_COLUMN_NAME - , PARENT_MENU_OBJID - , CHILD_TABLE_NAME - , CHILD_COLUMN_NAME - , CHILD_MENU_OBJID - , CLEAR_ON_PARENT_CHANGE - , SHOW_GROUP_LABEL - , EMPTY_PARENT_MESSAGE - , NO_OPTIONS_MESSAGE - , COMPANY_CODE - , IS_ACTIVE - , CREATED_BY - , CREATED_DATE - ) VALUES ( - #{relation_code} - , #{relation_name} - , #{description} - , #{parent_table_name} - , #{parent_column_name} - , #{parent_menu_objid} - , #{child_table_name} - , #{child_column_name} - , #{child_menu_objid} - , COALESCE(#{clear_on_parent_change}, 'Y') - , COALESCE(#{show_group_label}, 'Y') - , COALESCE(#{empty_parent_message}, '상위 항목을 먼저 선택하세요') - , COALESCE(#{no_options_message}, '선택 가능한 항목이 없습니다') - , #{company_code} - , 'Y' - , #{created_by} - , NOW() - ) - - - - UPDATE CATEGORY_VALUE_CASCADING_GROUP - SET - RELATION_NAME = COALESCE(#{relation_name}, RELATION_NAME) - , DESCRIPTION = COALESCE(#{description}, DESCRIPTION) - , PARENT_TABLE_NAME = COALESCE(#{parent_table_name}, PARENT_TABLE_NAME) - , PARENT_COLUMN_NAME = COALESCE(#{parent_column_name}, PARENT_COLUMN_NAME) - , PARENT_MENU_OBJID = COALESCE(#{parent_menu_objid}, PARENT_MENU_OBJID) - , CHILD_TABLE_NAME = COALESCE(#{child_table_name}, CHILD_TABLE_NAME) - , CHILD_COLUMN_NAME = COALESCE(#{child_column_name}, CHILD_COLUMN_NAME) - , CHILD_MENU_OBJID = COALESCE(#{child_menu_objid}, CHILD_MENU_OBJID) - , CLEAR_ON_PARENT_CHANGE = COALESCE(#{clear_on_parent_change}, CLEAR_ON_PARENT_CHANGE) - , SHOW_GROUP_LABEL = COALESCE(#{show_group_label}, SHOW_GROUP_LABEL) - , EMPTY_PARENT_MESSAGE = COALESCE(#{empty_parent_message}, EMPTY_PARENT_MESSAGE) - , NO_OPTIONS_MESSAGE = COALESCE(#{no_options_message}, NO_OPTIONS_MESSAGE) - , IS_ACTIVE = COALESCE(#{is_active}, IS_ACTIVE) - , UPDATED_BY = #{updated_by} - , UPDATED_DATE = NOW() - WHERE GROUP_ID = #{group_id} - - - - - UPDATE CATEGORY_VALUE_CASCADING_GROUP - SET - IS_ACTIVE = 'N' - , UPDATED_BY = #{updated_by} - , UPDATED_DATE = NOW() - WHERE GROUP_ID = #{group_id} - - - - - - - DELETE FROM CATEGORY_VALUE_CASCADING_MAPPING - WHERE GROUP_ID = #{group_id} - - - - INSERT INTO CATEGORY_VALUE_CASCADING_MAPPING ( - GROUP_ID - , PARENT_VALUE_CODE - , PARENT_VALUE_LABEL - , CHILD_VALUE_CODE - , CHILD_VALUE_LABEL - , DISPLAY_ORDER - , COMPANY_CODE - , IS_ACTIVE - , CREATED_DATE - ) VALUES ( - #{group_id} - , #{parent_value_code} - , #{parent_value_label} - , #{child_value_code} - , #{child_value_label} - , COALESCE(#{display_order}, 0) - , #{company_code} - , 'Y' - , NOW() - ) - - - diff --git a/backend-spring/src/main/resources/mapper/codeMerge.xml b/backend-spring/src/main/resources/mapper/codeMerge.xml deleted file mode 100644 index efac5d45..00000000 --- a/backend-spring/src/main/resources/mapper/codeMerge.xml +++ /dev/null @@ -1,30 +0,0 @@ - - - - - - - - diff --git a/backend-spring/src/main/resources/mapper/commonCode.xml b/backend-spring/src/main/resources/mapper/commonCode.xml index 934b2373..2f83d0a1 100644 --- a/backend-spring/src/main/resources/mapper/commonCode.xml +++ b/backend-spring/src/main/resources/mapper/commonCode.xml @@ -4,455 +4,436 @@ - + - SELECT - category_code, - category_name, - category_name_eng, - description, - sort_order, - is_active, - menu_objid, - company_code, - created_by, - updated_by, - created_date, - updated_date + CODE_INFO + , CODE_NAME + , CODE_NAME_ENG + , DESCRIPTION + , SORT_ORDER + , IS_ACTIVE + , MENU_OBJID + , COMPANY_CODE + , CREATED_BY + , UPDATED_BY + , CREATED_DATE + , UPDATED_DATE - FROM code_category + FROM CODE_INFO WHERE 1=1 AND ( - LOWER(category_code) LIKE LOWER(CONCAT('%', #{search}, '%')) - OR LOWER(category_name) LIKE LOWER(CONCAT('%', #{search}, '%')) - OR LOWER(COALESCE(category_name_eng, '')) LIKE LOWER(CONCAT('%', #{search}, '%')) + LOWER(CODE_INFO) LIKE LOWER(CONCAT('%', #{search}, '%')) + OR LOWER(CODE_NAME) LIKE LOWER(CONCAT('%', #{search}, '%')) + OR LOWER(COALESCE(CODE_NAME_ENG, '')) LIKE LOWER(CONCAT('%', #{search}, '%')) ) - AND is_active = #{is_active} - - - AND menu_objid = #{menu_objid} + AND IS_ACTIVE = #{is_active} - ORDER BY sort_order ASC, category_code ASC + ORDER BY SORT_ORDER ASC, CODE_INFO ASC - SELECT COUNT(*) - FROM code_category + FROM CODE_INFO WHERE 1=1 AND ( - LOWER(category_code) LIKE LOWER(CONCAT('%', #{search}, '%')) - OR LOWER(category_name) LIKE LOWER(CONCAT('%', #{search}, '%')) - OR LOWER(COALESCE(category_name_eng, '')) LIKE LOWER(CONCAT('%', #{search}, '%')) + LOWER(CODE_INFO) LIKE LOWER(CONCAT('%', #{search}, '%')) + OR LOWER(CODE_NAME) LIKE LOWER(CONCAT('%', #{search}, '%')) + OR LOWER(COALESCE(CODE_NAME_ENG, '')) LIKE LOWER(CONCAT('%', #{search}, '%')) ) - AND is_active = #{is_active} - - - AND menu_objid = #{menu_objid} + AND IS_ACTIVE = #{is_active} - SELECT - category_code, - category_name, - category_name_eng, - description, - sort_order, - is_active, - menu_objid, - company_code, - created_by, - updated_by, - created_date, - updated_date + CODE_INFO + , CODE_NAME + , CODE_NAME_ENG + , DESCRIPTION + , SORT_ORDER + , IS_ACTIVE + , MENU_OBJID + , COMPANY_CODE + , CREATED_BY + , UPDATED_BY + , CREATED_DATE + , UPDATED_DATE - FROM code_category + FROM CODE_INFO - WHERE category_code = #{category_code} + WHERE CODE_INFO = #{code_info} - - INSERT INTO code_category ( - category_code, - category_name, - category_name_eng, - description, - sort_order, - is_active, - menu_objid, - company_code, - created_by, - updated_by, - created_date, - updated_date + + INSERT INTO CODE_INFO ( + CODE_INFO + , CODE_NAME + , CODE_NAME_ENG + , DESCRIPTION + , SORT_ORDER + , IS_ACTIVE + , MENU_OBJID + , COMPANY_CODE + , CREATED_BY + , UPDATED_BY + , CREATED_DATE + , UPDATED_DATE ) VALUES ( - #{category_code}, - #{category_name}, - #{category_name_eng}, - #{description}, - #{sort_order}, - #{is_active}, - #{menu_objid}, - #{company_code}, - #{created_by}, - #{updated_by}, - NOW(), - NOW() + #{code_info} + , #{code_name} + , #{code_name_eng} + , #{description} + , #{sort_order} + , #{is_active} + , #{menu_objid} + , #{company_code} + , #{created_by} + , #{updated_by} + , NOW() + , NOW() ) - - UPDATE code_category + + UPDATE CODE_INFO - category_name = #{category_name}, - category_name_eng = #{category_name_eng}, - description = #{description}, - sort_order = #{sort_order}, - is_active = #{is_active}, - updated_by = #{updated_by}, - updated_date = NOW() + CODE_NAME = #{code_name}, + CODE_NAME_ENG = #{code_name_eng}, + DESCRIPTION = #{description}, + SORT_ORDER = #{sort_order}, + IS_ACTIVE = #{is_active}, + MENU_OBJID = #{menu_objid}, + UPDATED_BY = #{updated_by}, + UPDATED_DATE = NOW() - WHERE category_code = #{category_code} + WHERE CODE_INFO = #{code_info} - - DELETE FROM code_category + + DELETE FROM CODE_INFO - WHERE category_code = #{category_code} + WHERE CODE_INFO = #{code_info} - SELECT COUNT(*) - FROM code_category + FROM CODE_INFO - WHERE category_code = #{category_code} + WHERE CODE_INFO = #{code_info} - SELECT COUNT(*) - FROM code_category + FROM CODE_INFO WHERE 1=1 - AND category_code = #{value} - AND category_name = #{value} - AND category_name_eng = #{value} - AND category_code = #{value} + AND CODE_INFO = #{value} + AND CODE_NAME = #{value} + AND CODE_NAME_ENG = #{value} + AND CODE_INFO = #{value} - AND category_code != #{exclude_code} + AND CODE_INFO != #{exclude_code} - + - SELECT - code_category, - code_value, - code_name, - code_name_eng, - description, - sort_order, - is_active, - menu_objid, - company_code, - parent_code_value, - depth, - created_by, - updated_by, - created_date, - updated_date + CODE_DETAIL_ID + , CODE_INFO + , PARENT_DETAIL_ID + , CODE_VALUE + , CODE_NAME + , CODE_NAME_ENG + , DESCRIPTION + , DEPTH + , SORT_ORDER + , IS_ACTIVE + , COMPANY_CODE + , CREATED_BY + , UPDATED_BY + , CREATED_DATE + , UPDATED_DATE - FROM code_info + FROM CODE_DETAIL - WHERE code_category = #{category_code} + WHERE CODE_INFO = #{code_info} + + + AND PARENT_DETAIL_ID = #{parent_detail_id} + + + AND PARENT_DETAIL_ID IS NULL + + AND ( - LOWER(code_value) LIKE LOWER(CONCAT('%', #{search}, '%')) - OR LOWER(code_name) LIKE LOWER(CONCAT('%', #{search}, '%')) - OR LOWER(COALESCE(code_name_eng, '')) LIKE LOWER(CONCAT('%', #{search}, '%')) + LOWER(CODE_VALUE) LIKE LOWER(CONCAT('%', #{search}, '%')) + OR LOWER(CODE_NAME) LIKE LOWER(CONCAT('%', #{search}, '%')) + OR LOWER(COALESCE(CODE_NAME_ENG, '')) LIKE LOWER(CONCAT('%', #{search}, '%')) ) - AND is_active = #{is_active} + AND IS_ACTIVE = #{is_active} - ORDER BY sort_order ASC, code_value ASC + ORDER BY DEPTH ASC, SORT_ORDER ASC, CODE_VALUE ASC - SELECT COUNT(*) - FROM code_info + FROM CODE_DETAIL - WHERE code_category = #{category_code} + WHERE CODE_INFO = #{code_info} + + + AND PARENT_DETAIL_ID = #{parent_detail_id} + + + AND PARENT_DETAIL_ID IS NULL + + AND ( - LOWER(code_value) LIKE LOWER(CONCAT('%', #{search}, '%')) - OR LOWER(code_name) LIKE LOWER(CONCAT('%', #{search}, '%')) - OR LOWER(COALESCE(code_name_eng, '')) LIKE LOWER(CONCAT('%', #{search}, '%')) + LOWER(CODE_VALUE) LIKE LOWER(CONCAT('%', #{search}, '%')) + OR LOWER(CODE_NAME) LIKE LOWER(CONCAT('%', #{search}, '%')) + OR LOWER(COALESCE(CODE_NAME_ENG, '')) LIKE LOWER(CONCAT('%', #{search}, '%')) ) - AND is_active = #{is_active} + AND IS_ACTIVE = #{is_active} - SELECT - code_category, - code_value, - code_name, - code_name_eng, - description, - sort_order, - is_active, - menu_objid, - company_code, - parent_code_value, - depth, - created_by, - updated_by, - created_date, - updated_date + CODE_DETAIL_ID + , CODE_INFO + , PARENT_DETAIL_ID + , CODE_VALUE + , CODE_NAME + , CODE_NAME_ENG + , DESCRIPTION + , DEPTH + , SORT_ORDER + , IS_ACTIVE + , COMPANY_CODE + , CREATED_BY + , UPDATED_BY + , CREATED_DATE + , UPDATED_DATE - FROM code_info + FROM CODE_DETAIL - WHERE code_category = #{category_code} - AND code_value = #{code_value} + WHERE CODE_DETAIL_ID = #{code_detail_id} - - INSERT INTO code_info ( - code_category, - code_value, - code_name, - code_name_eng, - description, - sort_order, - is_active, - menu_objid, - company_code, - parent_code_value, - depth, - created_by, - updated_by, - created_date, - updated_date + + + + + INSERT INTO CODE_DETAIL ( + CODE_INFO + , PARENT_DETAIL_ID + , CODE_VALUE + , CODE_NAME + , CODE_NAME_ENG + , DESCRIPTION + , DEPTH + , SORT_ORDER + , IS_ACTIVE + , COMPANY_CODE + , CREATED_BY + , UPDATED_BY + , CREATED_DATE + , UPDATED_DATE ) VALUES ( - #{category_code}, - #{code_value}, - #{code_name}, - #{code_name_eng}, - #{description}, - #{sort_order}, - #{is_active}, - #{menu_objid}, - #{company_code}, - #{parent_code_value}, - #{depth}, - #{created_by}, - #{updated_by}, - NOW(), - NOW() + #{code_info} + , #{parent_detail_id} + , #{code_value} + , #{code_name} + , #{code_name_eng} + , #{description} + , #{depth} + , #{sort_order} + , #{is_active} + , #{company_code} + , #{created_by} + , #{updated_by} + , NOW() + , NOW() ) - - UPDATE code_info + + UPDATE CODE_DETAIL - code_name = #{code_name}, - code_name_eng = #{code_name_eng}, - description = #{description}, - sort_order = #{sort_order}, - is_active = #{is_active}, - parent_code_value = #{parent_code_value}, - depth = #{depth}, - updated_by = #{updated_by}, - updated_date = NOW() + CODE_VALUE = #{code_value}, + CODE_NAME = #{code_name}, + CODE_NAME_ENG = #{code_name_eng}, + DESCRIPTION = #{description}, + SORT_ORDER = #{sort_order}, + IS_ACTIVE = #{is_active}, + + PARENT_DETAIL_ID = #{parent_detail_id}, + DEPTH = #{depth}, + + UPDATED_BY = #{updated_by}, + UPDATED_DATE = NOW() - WHERE code_category = #{category_code} - AND code_value = #{code_value} + WHERE CODE_DETAIL_ID = #{code_detail_id} - - DELETE FROM code_info + + DELETE FROM CODE_DETAIL - WHERE code_category = #{category_code} - AND code_value = #{code_value} + WHERE CODE_DETAIL_ID = #{code_detail_id} - - UPDATE code_info - SET sort_order = #{sort_order}, - updated_date = NOW() - - WHERE code_category = #{category_code} - AND code_value = #{code_value} - - - - SELECT COUNT(*) - FROM code_info + FROM CODE_DETAIL - WHERE code_category = #{category_code} - AND code_value = #{code_value} + WHERE CODE_INFO = #{code_info} + AND CODE_VALUE = #{code_value} + + AND CODE_DETAIL_ID != #{exclude_id} + - SELECT COUNT(*) - FROM code_info + FROM CODE_DETAIL - WHERE code_category = #{category_code} - - - AND code_value = #{value} - AND code_name = #{value} - AND code_name_eng = #{value} - AND code_value = #{value} - - - AND code_value != #{exclude_code} - - - - - + SELECT COALESCE(DEPTH, 1) - FROM code_info + FROM CODE_DETAIL - WHERE code_category = #{category_code} - AND parent_code_value = #{code_value} + WHERE CODE_DETAIL_ID = #{code_detail_id} - - - - - - - - - - diff --git a/backend-spring/src/main/resources/mapper/entityReference.xml b/backend-spring/src/main/resources/mapper/entityReference.xml index ca94a17f..9ce79cb8 100644 --- a/backend-spring/src/main/resources/mapper/entityReference.xml +++ b/backend-spring/src/main/resources/mapper/entityReference.xml @@ -70,7 +70,7 @@ FROM code_info - WHERE code_category = #{code_category} + WHERE code_info = #{code_info} AND is_active = 'Y' AND (company_code = #{company_code} OR company_code = '*') diff --git a/backend-spring/src/main/resources/mapper/entitySearch.xml b/backend-spring/src/main/resources/mapper/entitySearch.xml index ea7f0db2..b8e6bb8b 100644 --- a/backend-spring/src/main/resources/mapper/entitySearch.xml +++ b/backend-spring/src/main/resources/mapper/entitySearch.xml @@ -38,17 +38,17 @@ @@ -62,7 +62,7 @@ FROM code_info - WHERE code_category = #{code_category} + WHERE code_info = #{code_info} AND code_value IN #{v} diff --git a/backend-spring/src/main/resources/mapper/meta.xml b/backend-spring/src/main/resources/mapper/meta.xml index 936a05c8..c4b69dd9 100644 --- a/backend-spring/src/main/resources/mapper/meta.xml +++ b/backend-spring/src/main/resources/mapper/meta.xml @@ -67,7 +67,7 @@ , REFERENCE_TABLE , REFERENCE_COLUMN , DISPLAY_COLUMN - , CODE_CATEGORY + , CODE_INFO , CODE_VALUE , COMPANY_CODE FROM TABLE_TYPE_COLUMNS diff --git a/backend-spring/src/main/resources/mapper/screenManagement.xml b/backend-spring/src/main/resources/mapper/screenManagement.xml index aa6b884e..23796ab2 100644 --- a/backend-spring/src/main/resources/mapper/screenManagement.xml +++ b/backend-spring/src/main/resources/mapper/screenManagement.xml @@ -1091,12 +1091,12 @@ - INSERT INTO CODE_CATEGORY ( + INSERT INTO CODE_INFO ( CATEGORY_CODE , CATEGORY_NAME , COMPANY_CODE @@ -1117,26 +1117,26 @@ * FROM CODE_INFO WHERE (COMPANY_CODE = #{source_company_code} OR COMPANY_CODE = '*') - AND CODE_CATEGORY = #{code_category} + AND CODE_INFO = #{code_info} INSERT INTO CODE_INFO ( - CODE_CATEGORY + CODE_INFO , CODE_VALUE , CODE_NAME , COMPANY_CODE , SORT_ORDER , IS_ACTIVE ) VALUES ( - #{code_category} + #{code_info} , #{code_value} , #{code_name} , #{target_company_code} , #{sort_order} , #{is_active} ) - ON CONFLICT (CODE_CATEGORY, CODE_VALUE, COMPANY_CODE) DO UPDATE SET + ON CONFLICT (CODE_INFO, CODE_VALUE, COMPANY_CODE) DO UPDATE SET CODE_NAME = EXCLUDED.CODE_NAME , SORT_ORDER = EXCLUDED.SORT_ORDER , IS_ACTIVE = EXCLUDED.IS_ACTIVE @@ -1359,7 +1359,7 @@ COLUMN_NAME , INPUT_TYPE , COLUMN_LABEL - , CODE_CATEGORY + , CODE_INFO , REFERENCE_TABLE , REFERENCE_COLUMN , DISPLAY_COLUMN diff --git a/backend-spring/src/main/resources/mapper/tableCategoryValue.xml b/backend-spring/src/main/resources/mapper/tableCategoryValue.xml deleted file mode 100644 index 414dd51a..00000000 --- a/backend-spring/src/main/resources/mapper/tableCategoryValue.xml +++ /dev/null @@ -1,470 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - INSERT INTO CATEGORY_VALUES ( - TABLE_NAME, COLUMN_NAME, VALUE_CODE, VALUE_LABEL, VALUE_ORDER, - PARENT_VALUE_ID, DEPTH, DESCRIPTION, COLOR, ICON, - IS_ACTIVE, IS_DEFAULT, COMPANY_CODE, MENU_OBJID, CREATED_BY - ) VALUES ( - #{table_name}, #{column_name}, #{value_code}, #{value_label}, #{value_order}, - #{parent_value_id}, #{depth}, #{description}, #{color}, #{icon}, - #{is_active}, #{is_default}, #{company_code}, #{menu_objid}, #{user_id} - ) - - - - UPDATE CATEGORY_VALUES - - VALUE_LABEL = #{value_label}, - VALUE_ORDER = #{value_order}, - DESCRIPTION = #{description}, - COLOR = #{color}, - ICON = #{icon}, - IS_ACTIVE = #{is_active}, - IS_DEFAULT = #{is_default}, - UPDATED_DATE = NOW(), - UPDATED_BY = #{user_id} - - WHERE VALUE_ID = #{value_id} - - AND (COMPANY_CODE = #{company_code} OR COMPANY_CODE = '*') - - - - - - - - - - - - - - - - - DELETE FROM CATEGORY_VALUES - WHERE VALUE_ID = #{value_id} - - AND (COMPANY_CODE = #{company_code} OR COMPANY_CODE = '*') - - - - - - - UPDATE CATEGORY_VALUES - SET IS_ACTIVE = FALSE, - UPDATED_DATE = NOW(), - UPDATED_BY = #{user_id} - WHERE VALUE_ID IN - - #{id} - - - AND (COMPANY_CODE = #{company_code} OR COMPANY_CODE = '*') - - - - - UPDATE CATEGORY_VALUES - SET VALUE_ORDER = #{value_order}, - UPDATED_DATE = NOW() - WHERE VALUE_ID = #{value_id} - - AND (COMPANY_CODE = #{company_code} OR COMPANY_CODE = '*') - - - - - - - - - - - - - - INSERT INTO CATEGORY_COLUMN_MAPPING ( - TABLE_NAME, LOGICAL_COLUMN_NAME, PHYSICAL_COLUMN_NAME, - MENU_OBJID, COMPANY_CODE, DESCRIPTION, CREATED_BY, UPDATED_BY - ) VALUES ( - #{table_name}, #{logical_column_name}, #{physical_column_name}, - #{menu_objid}, #{company_code}, #{description}, #{user_id}, #{user_id} - ) - ON CONFLICT (table_name, logical_column_name, menu_objid, company_code) - DO UPDATE SET - PHYSICAL_COLUMN_NAME = EXCLUDED.PHYSICAL_COLUMN_NAME, - DESCRIPTION = EXCLUDED.DESCRIPTION, - UPDATED_DATE = NOW(), - UPDATED_BY = EXCLUDED.UPDATED_BY - - - - - - DELETE FROM CATEGORY_COLUMN_MAPPING - WHERE MAPPING_ID = #{mapping_id} - - AND (COMPANY_CODE = #{company_code} OR COMPANY_CODE = '*') - - - - - DELETE FROM CATEGORY_COLUMN_MAPPING - WHERE TABLE_NAME = #{table_name} - AND LOGICAL_COLUMN_NAME = #{column_name} - - AND (COMPANY_CODE = #{company_code} OR COMPANY_CODE = '*') - - - - - - - - - - - - - - diff --git a/backend-spring/src/main/resources/mapper/tableManagement.xml b/backend-spring/src/main/resources/mapper/tableManagement.xml index 845fc12a..8b727d4e 100644 --- a/backend-spring/src/main/resources/mapper/tableManagement.xml +++ b/backend-spring/src/main/resources/mapper/tableManagement.xml @@ -57,7 +57,7 @@ , C.CHARACTER_MAXIMUM_LENGTH AS MAX_LENGTH , C.NUMERIC_PRECISION , C.NUMERIC_SCALE - , CL.CODE_CATEGORY + , CL.CODE_INFO , CL.CODE_VALUE , CL.REFERENCE_TABLE , CL.REFERENCE_COLUMN @@ -110,7 +110,7 @@ , C.CHARACTER_MAXIMUM_LENGTH AS MAX_LENGTH , C.NUMERIC_PRECISION , C.NUMERIC_SCALE - , COALESCE(TTC.CODE_CATEGORY, CL.CODE_CATEGORY) AS CODE_CATEGORY + , COALESCE(TTC.CODE_INFO, CL.CODE_INFO) AS CODE_INFO , COALESCE(TTC.CODE_VALUE, CL.CODE_VALUE) AS CODE_VALUE , COALESCE(TTC.REFERENCE_TABLE, CL.REFERENCE_TABLE) AS REFERENCE_TABLE , COALESCE(TTC.REFERENCE_COLUMN, CL.REFERENCE_COLUMN) AS REFERENCE_COLUMN @@ -253,7 +253,7 @@ , DESCRIPTION , DISPLAY_ORDER , IS_VISIBLE - , CODE_CATEGORY + , CODE_INFO , CODE_VALUE , REFERENCE_TABLE , REFERENCE_COLUMN @@ -275,7 +275,7 @@ , COLUMN_LABEL , INPUT_TYPE , DETAIL_SETTINGS - , CODE_CATEGORY + , CODE_INFO , CODE_VALUE , REFERENCE_TABLE , REFERENCE_COLUMN @@ -293,7 +293,7 @@ , #{column_label} , #{input_type} , #{detail_settings}::JSONB - , #{code_category} + , #{code_info} , #{code_value} , #{reference_table} , #{reference_column} @@ -311,7 +311,7 @@ COLUMN_LABEL = COALESCE(EXCLUDED.COLUMN_LABEL, TABLE_TYPE_COLUMNS.COLUMN_LABEL) , INPUT_TYPE = COALESCE(EXCLUDED.INPUT_TYPE, TABLE_TYPE_COLUMNS.INPUT_TYPE) , DETAIL_SETTINGS = COALESCE(EXCLUDED.DETAIL_SETTINGS, TABLE_TYPE_COLUMNS.DETAIL_SETTINGS) - , CODE_CATEGORY = EXCLUDED.CODE_CATEGORY + , CODE_INFO = EXCLUDED.CODE_INFO , CODE_VALUE = EXCLUDED.CODE_VALUE , REFERENCE_TABLE = EXCLUDED.REFERENCE_TABLE , REFERENCE_COLUMN = EXCLUDED.REFERENCE_COLUMN @@ -354,7 +354,7 @@ , REFERENCE_TABLE = CASE WHEN #{clear_entity} = 'true' THEN NULL ELSE TABLE_TYPE_COLUMNS.REFERENCE_TABLE END , REFERENCE_COLUMN= CASE WHEN #{clear_entity} = 'true' THEN NULL ELSE TABLE_TYPE_COLUMNS.REFERENCE_COLUMN END , DISPLAY_COLUMN = CASE WHEN #{clear_entity} = 'true' THEN NULL ELSE TABLE_TYPE_COLUMNS.DISPLAY_COLUMN END - , CODE_CATEGORY = CASE WHEN #{clear_code} = 'true' THEN NULL ELSE TABLE_TYPE_COLUMNS.CODE_CATEGORY END + , CODE_INFO = CASE WHEN #{clear_code} = 'true' THEN NULL ELSE TABLE_TYPE_COLUMNS.CODE_INFO END , CODE_VALUE = CASE WHEN #{clear_code} = 'true' THEN NULL ELSE TABLE_TYPE_COLUMNS.CODE_VALUE END , CATEGORY_REF = CASE WHEN #{clear_category} = 'true' THEN NULL ELSE TABLE_TYPE_COLUMNS.CATEGORY_REF END , UPDATED_DATE = NOW() diff --git a/frontend/app/(main)/admin/audit-log/page.tsx b/frontend/app/(main)/admin/audit-log/page.tsx index c0ae89e2..2167a3b9 100644 --- a/frontend/app/(main)/admin/audit-log/page.tsx +++ b/frontend/app/(main)/admin/audit-log/page.tsx @@ -78,7 +78,7 @@ const RESOURCE_TYPE_CONFIG: Record< USER: { label: "사용자", icon: User, color: "bg-amber-100 text-orange-700" }, ROLE: { label: "권한", icon: Shield, color: "bg-destructive/10 text-destructive" }, COMPANY: { label: "회사", icon: Building2, color: "bg-indigo-100 text-indigo-700" }, - CODE_CATEGORY: { label: "코드 카테고리", icon: Hash, color: "bg-cyan-100 text-cyan-700" }, + CODE_INFO: { label: "코드 카테고리", icon: Hash, color: "bg-cyan-100 text-cyan-700" }, CODE: { label: "코드", icon: Hash, color: "bg-cyan-100 text-cyan-700" }, DATA: { label: "데이터", icon: Database, color: "bg-muted text-foreground" }, TABLE: { label: "테이블", icon: Database, color: "bg-muted text-foreground" }, diff --git a/frontend/app/(main)/admin/auto-fill/page.tsx b/frontend/app/(main)/admin/auto-fill/page.tsx deleted file mode 100644 index 64e5e789..00000000 --- a/frontend/app/(main)/admin/auto-fill/page.tsx +++ /dev/null @@ -1,21 +0,0 @@ -"use client"; - -import { useEffect } from "react"; -import { useRouter } from "next/navigation"; - -/** - * 기존 자동입력 페이지 → 통합 관리 페이지로 리다이렉트 - */ -export default function AutoFillRedirect() { - const router = useRouter(); - - useEffect(() => { - router.replace("/admin/cascading-management?tab=autofill"); - }, [router]); - - return ( -
-
리다이렉트 중...
-
- ); -} diff --git a/frontend/app/(main)/admin/cascading-management/page.tsx b/frontend/app/(main)/admin/cascading-management/page.tsx deleted file mode 100644 index c36d8ae0..00000000 --- a/frontend/app/(main)/admin/cascading-management/page.tsx +++ /dev/null @@ -1,115 +0,0 @@ -"use client"; - -import React, { useState, useEffect } from "react"; -import { useSearchParams, useRouter } from "next/navigation"; -import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs"; -import { Link2, Layers, Filter, FormInput, Ban, Tags, Columns } from "lucide-react"; - -// 탭별 컴포넌트 -import CascadingRelationsTab from "./tabs/CascadingRelationsTab"; -import AutoFillTab from "./tabs/AutoFillTab"; -import HierarchyTab from "./tabs/HierarchyTab"; -import ConditionTab from "./tabs/ConditionTab"; -import MutualExclusionTab from "./tabs/MutualExclusionTab"; -import CategoryValueCascadingTab from "./tabs/CategoryValueCascadingTab"; -import HierarchyColumnTab from "./tabs/HierarchyColumnTab"; - -export default function CascadingManagementPage() { - const searchParams = useSearchParams(); - const router = useRouter(); - const [activeTab, setActiveTab] = useState("relations"); - - // URL 쿼리 파라미터에서 탭 설정 - useEffect(() => { - const tab = searchParams.get("tab"); - if (tab && ["relations", "hierarchy", "condition", "autofill", "exclusion", "category-value", "hierarchy-column"].includes(tab)) { - setActiveTab(tab); - } - }, [searchParams]); - - // 탭 변경 시 URL 업데이트 - const handleTabChange = (value: string) => { - setActiveTab(value); - const url = new URL(window.location.href); - url.searchParams.set("tab", value); - router.replace(url.pathname + url.search); - }; - - return ( -
-
- {/* 페이지 헤더 */} -
-

연쇄 드롭다운 통합 관리

-

- 연쇄 드롭다운, 자동 입력, 다단계 계층, 조건부 필터 등을 관리합니다. -

-
- - {/* 탭 네비게이션 */} - - - - - 2단계 연쇄관계 - 연쇄 - - - - 다단계 계층 - 계층 - - - - 조건부 필터 - 조건 - - - - 자동 입력 - 자동 - - - - 상호 배제 - 배제 - - - - 카테고리값 - 카테고리 - - - - {/* 탭 컨텐츠 */} -
- - - - - - - - - - - - - - - - - - - - - - - -
-
-
-
- ); -} - diff --git a/frontend/app/(main)/admin/cascading-management/tabs/AutoFillTab.tsx b/frontend/app/(main)/admin/cascading-management/tabs/AutoFillTab.tsx deleted file mode 100644 index d5b58018..00000000 --- a/frontend/app/(main)/admin/cascading-management/tabs/AutoFillTab.tsx +++ /dev/null @@ -1,687 +0,0 @@ -"use client"; - -import React, { useState, useEffect, useCallback } from "react"; -import { Button } from "@/components/ui/button"; -import { Input } from "@/components/ui/input"; -import { Label } from "@/components/ui/label"; -import { Textarea } from "@/components/ui/textarea"; -import { Switch } from "@/components/ui/switch"; -import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "@/components/ui/select"; -import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow } from "@/components/ui/table"; -import { - Dialog, - DialogContent, - DialogDescription, - DialogFooter, - DialogHeader, - DialogTitle, -} from "@/components/ui/dialog"; -import { - AlertDialog, - AlertDialogAction, - AlertDialogCancel, - AlertDialogContent, - AlertDialogDescription, - AlertDialogFooter, - AlertDialogHeader, - AlertDialogTitle, -} from "@/components/ui/alert-dialog"; -import { Command, CommandEmpty, CommandGroup, CommandInput, CommandItem, CommandList } from "@/components/ui/command"; -import { Popover, PopoverContent, PopoverTrigger } from "@/components/ui/popover"; -import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "@/components/ui/card"; -import { Badge } from "@/components/ui/badge"; -import { Checkbox } from "@/components/ui/checkbox"; -import { Separator } from "@/components/ui/separator"; -import { - Check, - ChevronsUpDown, - Plus, - Pencil, - Trash2, - Search, - RefreshCw, - ArrowRight, - X, - GripVertical, -} from "lucide-react"; -import { toast } from "sonner"; -import { showErrorToast } from "@/lib/utils/toastUtils"; -import { cn } from "@/lib/utils"; -import { cascadingAutoFillApi, AutoFillGroup, AutoFillMapping } from "@/lib/api/cascadingAutoFill"; -import { tableManagementApi } from "@/lib/api/tableManagement"; - -interface TableColumn { - columnName: string; - columnLabel?: string; - dataType?: string; -} - -export default function AutoFillTab() { - // 목록 상태 - const [groups, setGroups] = useState([]); - const [loading, setLoading] = useState(true); - const [searchText, setSearchText] = useState(""); - - // 모달 상태 - const [isModalOpen, setIsModalOpen] = useState(false); - const [isDeleteDialogOpen, setIsDeleteDialogOpen] = useState(false); - const [editingGroup, setEditingGroup] = useState(null); - const [deletingGroupCode, setDeletingGroupCode] = useState(null); - - // 테이블/컬럼 목록 - const [tableList, setTableList] = useState>([]); - const [masterColumns, setMasterColumns] = useState([]); - - // 폼 데이터 - const [formData, setFormData] = useState({ - groupName: "", - description: "", - masterTable: "", - masterValueColumn: "", - masterLabelColumn: "", - isActive: "Y", - }); - - // 매핑 데이터 - const [mappings, setMappings] = useState([]); - - // 테이블 Combobox 상태 - const [tableComboOpen, setTableComboOpen] = useState(false); - - // 목록 로드 - const loadGroups = useCallback(async () => { - setLoading(true); - try { - const response = await cascadingAutoFillApi.getGroups(); - if (response.success && response.data) { - setGroups(response.data); - } - } catch (error) { - console.error("그룹 목록 로드 실패:", error); - showErrorToast("그룹 목록을 불러오는 데 실패했습니다", error, { guidance: "네트워크 연결을 확인해 주세요." }); - } finally { - setLoading(false); - } - }, []); - - // 테이블 목록 로드 - const loadTableList = useCallback(async () => { - try { - const response = await tableManagementApi.getTableList(); - if (response.success && response.data) { - setTableList(response.data); - } - } catch (error) { - console.error("테이블 목록 로드 실패:", error); - } - }, []); - - // 테이블 컬럼 로드 - const loadColumns = useCallback(async (tableName: string) => { - if (!tableName) { - setMasterColumns([]); - return; - } - try { - const response = await tableManagementApi.getColumnList(tableName); - if (response.success && response.data?.columns) { - setMasterColumns( - response.data.columns.map((col: any) => ({ - columnName: col.columnName || col.column_name, - columnLabel: col.columnLabel || col.column_label || col.columnName, - dataType: col.dataType || col.data_type, - })), - ); - } - } catch (error) { - console.error("컬럼 목록 로드 실패:", error); - setMasterColumns([]); - } - }, []); - - useEffect(() => { - loadGroups(); - loadTableList(); - }, [loadGroups, loadTableList]); - - // 테이블 변경 시 컬럼 로드 - useEffect(() => { - if (formData.masterTable) { - loadColumns(formData.masterTable); - } - }, [formData.masterTable, loadColumns]); - - // 필터된 목록 - const filteredGroups = groups.filter( - (g) => - g.groupCode.toLowerCase().includes(searchText.toLowerCase()) || - g.groupName.toLowerCase().includes(searchText.toLowerCase()) || - g.masterTable?.toLowerCase().includes(searchText.toLowerCase()), - ); - - // 모달 열기 (생성) - const handleOpenCreate = () => { - setEditingGroup(null); - setFormData({ - groupName: "", - description: "", - masterTable: "", - masterValueColumn: "", - masterLabelColumn: "", - isActive: "Y", - }); - setMappings([]); - setMasterColumns([]); - setIsModalOpen(true); - }; - - // 모달 열기 (수정) - const handleOpenEdit = async (group: AutoFillGroup) => { - setEditingGroup(group); - - // 상세 정보 로드 - const detailResponse = await cascadingAutoFillApi.getGroupDetail(group.groupCode); - if (detailResponse.success && detailResponse.data) { - const detail = detailResponse.data; - - // 컬럼 먼저 로드 - if (detail.masterTable) { - await loadColumns(detail.masterTable); - } - - setFormData({ - groupCode: detail.groupCode, - groupName: detail.groupName, - description: detail.description || "", - masterTable: detail.masterTable, - masterValueColumn: detail.masterValueColumn, - masterLabelColumn: detail.masterLabelColumn || "", - isActive: detail.isActive || "Y", - }); - - // 매핑 데이터 변환 (snake_case → camelCase) - const convertedMappings = (detail.mappings || []).map((m: any) => ({ - sourceColumn: m.source_column || m.sourceColumn, - targetField: m.target_field || m.targetField, - targetLabel: m.target_label || m.targetLabel || "", - isEditable: m.is_editable || m.isEditable || "Y", - isRequired: m.is_required || m.isRequired || "N", - defaultValue: m.default_value || m.defaultValue || "", - sortOrder: m.sort_order || m.sortOrder || 0, - })); - setMappings(convertedMappings); - } - - setIsModalOpen(true); - }; - - // 삭제 확인 - const handleDeleteConfirm = (groupCode: string) => { - setDeletingGroupCode(groupCode); - setIsDeleteDialogOpen(true); - }; - - // 삭제 실행 - const handleDelete = async () => { - if (!deletingGroupCode) return; - - try { - const response = await cascadingAutoFillApi.deleteGroup(deletingGroupCode); - if (response.success) { - toast.success("자동 입력 그룹이 삭제되었습니다."); - loadGroups(); - } else { - toast.error(response.error || "삭제에 실패했습니다."); - } - } catch (error) { - toast.error("삭제 중 오류가 발생했습니다."); - } finally { - setIsDeleteDialogOpen(false); - setDeletingGroupCode(null); - } - }; - - // 저장 - const handleSave = async () => { - // 유효성 검사 - if (!formData.groupName || !formData.masterTable || !formData.masterValueColumn) { - toast.error("필수 항목을 모두 입력해주세요."); - return; - } - - try { - const saveData = { - ...formData, - mappings, - }; - - let response; - if (editingGroup) { - response = await cascadingAutoFillApi.updateGroup(editingGroup.groupCode!, saveData); - } else { - response = await cascadingAutoFillApi.createGroup(saveData); - } - - if (response.success) { - toast.success(editingGroup ? "수정되었습니다." : "생성되었습니다."); - setIsModalOpen(false); - loadGroups(); - } else { - toast.error(response.error || "저장에 실패했습니다."); - } - } catch (error) { - showErrorToast("자동입력 설정 저장에 실패했습니다", error, { guidance: "입력 데이터를 확인하고 다시 시도해 주세요." }); - } - }; - - // 매핑 추가 - const handleAddMapping = () => { - setMappings([ - ...mappings, - { - sourceColumn: "", - targetField: "", - targetLabel: "", - isEditable: "Y", - isRequired: "N", - defaultValue: "", - sortOrder: mappings.length + 1, - }, - ]); - }; - - // 매핑 삭제 - const handleRemoveMapping = (index: number) => { - setMappings(mappings.filter((_, i) => i !== index)); - }; - - // 매핑 수정 - const handleMappingChange = (index: number, field: keyof AutoFillMapping, value: any) => { - const updated = [...mappings]; - updated[index] = { ...updated[index], [field]: value }; - setMappings(updated); - }; - - return ( -
- {/* 검색 및 액션 */} - - -
-
- - setSearchText(e.target.value)} - className="pl-10" - /> -
- -
-
-
- - {/* 목록 */} - - -
-
- 자동 입력 그룹 - - 마스터 선택 시 여러 필드를 자동으로 입력합니다. (총 {filteredGroups.length}개) - -
- -
-
- - {loading ? ( -
- - 로딩 중... -
- ) : filteredGroups.length === 0 ? ( -
- {searchText ? "검색 결과가 없습니다." : "등록된 자동 입력 그룹이 없습니다."} -
- ) : ( - - - - 그룹 코드 - 그룹명 - 마스터 테이블 - 매핑 수 - 상태 - 작업 - - - - {filteredGroups.map((group) => ( - - {group.groupCode} - {group.groupName} - {group.masterTable} - - {group.mappingCount || 0}개 - - - - {group.isActive === "Y" ? "활성" : "비활성"} - - - - - - - - ))} - -
- )} -
-
- - {/* 생성/수정 모달 */} - - - - {editingGroup ? "자동 입력 그룹 수정" : "자동 입력 그룹 생성"} - 마스터 데이터 선택 시 자동으로 입력할 필드들을 설정합니다. - - -
- {/* 기본 정보 */} -
-

기본 정보

- -
- - setFormData({ ...formData, groupName: e.target.value })} - placeholder="예: 고객사 정보 자동입력" - /> -
- -
- - +
+
+
+ + +
+
+ 2 +

코드 모양 고르기

+ 자주 쓰는 형태 중 고르거나, 빈 상태에서 직접 만들 수 있어요 +
+
+ + + + + + + + + +
+
+ + +
+
+ 3 +

어디에 쓸지 정하기

+ 지금 정하거나 나중에 연결할 수 있어요 +
+ +
+ + +
+
+ 만들면 다음 코드부터 발번 시작 → SO-2026-05-0001 +
+
+ + +
+
+
+ + + +
+
+
+

+ 수주번호 + 사용 중 +

+
+ 생성 2026-03-12 by gbpark + 마지막 수정 2026-05-14 16:22 + 지금까지 142건 발번 +
+
+
+ + +
+
+ + +
+
+ 이 채번이 만드는 코드 + SO-YYYY-MM-#### +
+
+
+ 고정 + SO +
+ - +
+ 년도 + 2026 +
+ - +
+ + 05 +
+ - +
+ 순번 + 0142 +
+
+
+ 다음에 만들어질 코드: SO-2026-05-0143 + · 매월 1일에 순번 초기화 +
+
+ + +
+
+

코드를 이루는 조각

+ 4개 + 조각을 클릭해서 편집 · 사이에 마우스 올리면 추가 가능 +
+ +
+
+ +
+
+ +
+
1번고정text
+ SO + × +
+ - +
+
2번년도YYYY
+ 2026 + × +
+ - +
+
3번MM
+ 05 + × +
+ - +
+
4번순번4자리
+ 0143 + × +
+ +
+ +
+ 조각 종류: + + + + + +
+
+ + +
+
+
+ 2번 조각 + 날짜 설정 +
+ +
+
+
+ +
+ + + + + + +
+
+
+ +
+ + + + +
+ 매월 1일 00:00 에 순번이 1 부터 다시 시작 +
+
+
+
+ +
+
+ 저장하지 않은 변경 1건 있음 +
+
+ + +
+
+
+ + + + + + + + diff --git a/notes/gbpark/2026-05-15-numbering-rule-clean.html b/notes/gbpark/2026-05-15-numbering-rule-clean.html new file mode 100644 index 00000000..332a39ca --- /dev/null +++ b/notes/gbpark/2026-05-15-numbering-rule-clean.html @@ -0,0 +1,1238 @@ + + + + +채번 관리 — 정갈 버전 (v5 clean) + + + + + +
+ + +
+
+

채번 관리

+ + 14 규칙 · 9 연결 · 5 미사용 + +
+
+ + + +
+
+ +
+ + + + + +
+ + +
+
+
+
+

수주번호

+ 사용 중 + NR-001 +
+
+ 생성 2026-03-12 + 수정 2026-05-14 16:22 + by gbpark +
+
+
+
+ + + +
+
+ + +
+
+ 현재 발번 + SO-2026-05-0142 + 시퀀스 142 +
+ + +
+ + +
+
+

코드 구성

+ 4 / 8 + 파트 클릭 → 아래 인스펙터에서 편집 +
+ +
+
+ +
+
+ 1 +
+ TEXT + SO +
+ × +
+ - +
+ 2 +
+ DATE · YYYY + 2026 +
+ × +
+ - +
+ 3 +
+ DATE · MM + 05 +
+ × +
+ - +
+ 4 +
+ SEQ · 4d + 0143 +
+ × +
+ +
+ +
+ + 파트: + + + + + + +
+ + +
+
+
+ #2 + DATE 파트 설정 +
+ +
+
+
+ +
+ + + + + + +
+
+
+ +
+ + + + +
+
+
+
+
+ + +
+ +
+
+

연결된 컬럼

+ 1 + 이 채번이 적용된 사용처 +
+
+
+
+ SALES_ORDER + · + ORDER_NO +
+
단일 연결
+
+
+ 발번 + 142 +
+ +
+ +
+ + +
+
+

시퀀스

+ 월별 리셋 +
+
+
+ 현재 + 142 +
+
+ 다음 + 143 +
+
+
+ + + +
+
+ + + 운영 중인 채번입니다. 시퀀스 수정은 기존 발번 코드와 충돌 가능. + numbering_rule_sequences 재시작됨. + +
+
+
+ + +
+
+ 저장되지 않은 변경 1건 +
+
+ + +
+
+ +
+
+
+ + + +