Files
invyone/backend-spring/src/main/java/com/erp/service/CascadingHierarchyService.java
T

252 lines
12 KiB
Java

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<String, Object> getCascadingHierarchyGroupList(Map<String, Object> params) {
commonService.applyCompanyCodeFilter(params);
commonService.applyPagination(params);
int totalCount = sqlSession.selectOne(NS + "getCascadingHierarchyGroupListCnt", params);
List<Map<String, Object>> list = sqlSession.selectList(NS + "getCascadingHierarchyGroupList", params);
return commonService.buildListResponse(list, totalCount, params);
}
public Map<String, Object> getCascadingHierarchyGroupDetail(Map<String, Object> params) {
commonService.applyCompanyCodeFilter(params);
Map<String, Object> group = sqlSession.selectOne(NS + "getCascadingHierarchyGroupByCode", params);
if (group == null) return null;
Map<String, Object> levelParams = new HashMap<>();
levelParams.put("group_code", params.get("group_code"));
levelParams.put("company_code", group.get("company_code"));
List<Map<String, Object>> levels = sqlSession.selectList(NS + "getCascadingHierarchyLevelList", levelParams);
Map<String, Object> result = new HashMap<>(group);
result.put("levels", levels);
return result;
}
@Transactional
public Map<String, Object> insertCascadingHierarchyGroup(Map<String, Object> 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<String, Object> 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<String, Object> level = (Map<String, Object>) l;
Map<String, Object> 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<String, Object> updateCascadingHierarchyGroup(Map<String, Object> params) {
commonService.applyCompanyCodeFilter(params);
params.put("updated_by", params.getOrDefault("user_id", "system"));
Map<String, Object> 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<String, Object> params) {
commonService.applyCompanyCodeFilter(params);
Map<String, Object> 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<String, Object> 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<String, Object> addCascadingHierarchyLevel(Map<String, Object> params) {
commonService.applyCompanyCodeFilter(params);
String groupCode = (String) params.get("group_code");
Map<String, Object> groupParams = new HashMap<>();
groupParams.put("group_code", groupCode);
groupParams.put("company_code", params.get("company_code"));
Map<String, Object> 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<String, Object> updateCascadingHierarchyLevel(Map<String, Object> params) {
commonService.applyCompanyCodeFilter(params);
Map<String, Object> existing = sqlSession.selectOne(NS + "getCascadingHierarchyLevelInfo", params);
if (existing == null) return null;
sqlSession.update(NS + "updateCascadingHierarchyLevel", params);
return params;
}
@Transactional
public boolean deleteCascadingHierarchyLevel(Map<String, Object> params) {
commonService.applyCompanyCodeFilter(params);
Map<String, Object> existing = sqlSession.selectOne(NS + "getCascadingHierarchyLevelInfo", params);
if (existing == null) return false;
sqlSession.delete(NS + "deleteCascadingHierarchyLevel", params);
return true;
}
public Map<String, Object> getLevelOptions(Map<String, Object> params) {
commonService.applyCompanyCodeFilter(params);
String companyCode = (String) params.get("company_code");
Map<String, Object> 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<Object> 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<Map<String, Object>> options = jdbcTemplate.queryForList(sql.toString(), sqlParams.toArray());
Map<String, Object> 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<String, Object> 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;
}
}
}