Commit 0017a259116cfd31ab45bca69435bd7e09bf77c0
1 parent
7eec9887
feat(mod): module create error branches REQ-MOD-001
Showing
2 changed files
with
62 additions
and
1 deletions
backend/src/main/java/com/xly/erp/module/mod/service/impl/ModuleServiceImpl.java
| @@ -8,15 +8,19 @@ import com.xly.erp.module.mod.dto.CreateModuleDTO; | @@ -8,15 +8,19 @@ import com.xly.erp.module.mod.dto.CreateModuleDTO; | ||
| 8 | import com.xly.erp.module.mod.entity.Module; | 8 | import com.xly.erp.module.mod.entity.Module; |
| 9 | import com.xly.erp.module.mod.mapper.ModuleMapper; | 9 | import com.xly.erp.module.mod.mapper.ModuleMapper; |
| 10 | import com.xly.erp.module.mod.service.ModuleService; | 10 | import com.xly.erp.module.mod.service.ModuleService; |
| 11 | +import org.springframework.dao.DuplicateKeyException; | ||
| 11 | import org.springframework.stereotype.Service; | 12 | import org.springframework.stereotype.Service; |
| 12 | import org.springframework.transaction.annotation.Transactional; | 13 | import org.springframework.transaction.annotation.Transactional; |
| 13 | 14 | ||
| 14 | import java.time.LocalDateTime; | 15 | import java.time.LocalDateTime; |
| 16 | +import java.util.Set; | ||
| 15 | 17 | ||
| 16 | @Service | 18 | @Service |
| 17 | @Transactional(rollbackFor = Exception.class) | 19 | @Transactional(rollbackFor = Exception.class) |
| 18 | public class ModuleServiceImpl implements ModuleService { | 20 | public class ModuleServiceImpl implements ModuleService { |
| 19 | 21 | ||
| 22 | + private static final Set<String> DISPLAY_TYPES = Set.of("手机端", "前端业务", "系统配置", "接口"); | ||
| 23 | + | ||
| 20 | private final ModuleMapper moduleMapper; | 24 | private final ModuleMapper moduleMapper; |
| 21 | private final TenantProperties tenant; | 25 | private final TenantProperties tenant; |
| 22 | private final StubSecurityProperties stub; | 26 | private final StubSecurityProperties stub; |
| @@ -31,6 +35,9 @@ public class ModuleServiceImpl implements ModuleService { | @@ -31,6 +35,9 @@ public class ModuleServiceImpl implements ModuleService { | ||
| 31 | 35 | ||
| 32 | @Override | 36 | @Override |
| 33 | public Integer create(CreateModuleDTO dto) { | 37 | public Integer create(CreateModuleDTO dto) { |
| 38 | + if (!DISPLAY_TYPES.contains(dto.getSDisplayType())) { | ||
| 39 | + throw new BizException(40010, "显示类型枚举不合法"); | ||
| 40 | + } | ||
| 34 | if (dto.getIParentId() != null && !moduleMapper.existsActiveById(dto.getIParentId())) { | 41 | if (dto.getIParentId() != null && !moduleMapper.existsActiveById(dto.getIParentId())) { |
| 35 | throw new BizException(40021, "父模块不存在或已删除"); | 42 | throw new BizException(40021, "父模块不存在或已删除"); |
| 36 | } | 43 | } |
| @@ -51,7 +58,11 @@ public class ModuleServiceImpl implements ModuleService { | @@ -51,7 +58,11 @@ public class ModuleServiceImpl implements ModuleService { | ||
| 51 | m.setSCreatedBy(authedUserNo != null ? authedUserNo : stub.getStubUserNo()); | 58 | m.setSCreatedBy(authedUserNo != null ? authedUserNo : stub.getStubUserNo()); |
| 52 | m.setBDeleted(false); | 59 | m.setBDeleted(false); |
| 53 | 60 | ||
| 54 | - moduleMapper.insert(m); | 61 | + try { |
| 62 | + moduleMapper.insert(m); | ||
| 63 | + } catch (DuplicateKeyException e) { | ||
| 64 | + throw new BizException(40020, "存储过程名称已存在"); | ||
| 65 | + } | ||
| 55 | return m.getIIncrement(); | 66 | return m.getIIncrement(); |
| 56 | } | 67 | } |
| 57 | } | 68 | } |
backend/src/test/java/com/xly/erp/module/mod/service/ModuleServiceImplTest.java
| @@ -11,8 +11,12 @@ import org.junit.jupiter.api.AfterEach; | @@ -11,8 +11,12 @@ import org.junit.jupiter.api.AfterEach; | ||
| 11 | import org.junit.jupiter.api.BeforeEach; | 11 | import org.junit.jupiter.api.BeforeEach; |
| 12 | import org.junit.jupiter.api.Test; | 12 | import org.junit.jupiter.api.Test; |
| 13 | import org.mockito.ArgumentCaptor; | 13 | import org.mockito.ArgumentCaptor; |
| 14 | +import org.springframework.dao.DuplicateKeyException; | ||
| 15 | +import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; | ||
| 14 | import org.springframework.security.core.context.SecurityContextHolder; | 16 | import org.springframework.security.core.context.SecurityContextHolder; |
| 15 | 17 | ||
| 18 | +import java.util.Collections; | ||
| 19 | + | ||
| 16 | import static org.assertj.core.api.Assertions.assertThat; | 20 | import static org.assertj.core.api.Assertions.assertThat; |
| 17 | import static org.assertj.core.api.Assertions.assertThatThrownBy; | 21 | import static org.assertj.core.api.Assertions.assertThatThrownBy; |
| 18 | import static org.mockito.ArgumentMatchers.any; | 22 | import static org.mockito.ArgumentMatchers.any; |
| @@ -82,6 +86,52 @@ class ModuleServiceImplTest { | @@ -82,6 +86,52 @@ class ModuleServiceImplTest { | ||
| 82 | verify(moduleMapper, never()).insert(any(Module.class)); | 86 | verify(moduleMapper, never()).insert(any(Module.class)); |
| 83 | } | 87 | } |
| 84 | 88 | ||
| 89 | + @Test | ||
| 90 | + void createWithInvalidDisplayType_throws40010() { | ||
| 91 | + CreateModuleDTO dto = baseDto(); | ||
| 92 | + dto.setSDisplayType("未知"); | ||
| 93 | + | ||
| 94 | + assertThatThrownBy(() -> service.create(dto)) | ||
| 95 | + .isInstanceOf(BizException.class) | ||
| 96 | + .hasFieldOrPropertyWithValue("code", 40010); | ||
| 97 | + verify(moduleMapper, never()).insert(any(Module.class)); | ||
| 98 | + } | ||
| 99 | + | ||
| 100 | + @Test | ||
| 101 | + void createWithNullParentId_skipsParentCheck() { | ||
| 102 | + CreateModuleDTO dto = baseDto(); | ||
| 103 | + dto.setIParentId(null); | ||
| 104 | + | ||
| 105 | + service.create(dto); | ||
| 106 | + | ||
| 107 | + verify(moduleMapper, never()).findActiveFlagById(any()); | ||
| 108 | + verify(moduleMapper, times(1)).insert(any(Module.class)); | ||
| 109 | + } | ||
| 110 | + | ||
| 111 | + @Test | ||
| 112 | + void mapperDuplicateKey_throws40020() { | ||
| 113 | + CreateModuleDTO dto = baseDto(); | ||
| 114 | + when(moduleMapper.insert(any(Module.class))) | ||
| 115 | + .thenThrow(new DuplicateKeyException("uk_procedure_name")); | ||
| 116 | + | ||
| 117 | + assertThatThrownBy(() -> service.create(dto)) | ||
| 118 | + .isInstanceOf(BizException.class) | ||
| 119 | + .hasFieldOrPropertyWithValue("code", 40020); | ||
| 120 | + } | ||
| 121 | + | ||
| 122 | + @Test | ||
| 123 | + void usesAuthenticatedUserNoAsCreatedBy() { | ||
| 124 | + SecurityContextHolder.getContext().setAuthentication( | ||
| 125 | + new UsernamePasswordAuthenticationToken("ALICE", null, Collections.emptyList())); | ||
| 126 | + CreateModuleDTO dto = baseDto(); | ||
| 127 | + | ||
| 128 | + service.create(dto); | ||
| 129 | + | ||
| 130 | + ArgumentCaptor<Module> captor = ArgumentCaptor.forClass(Module.class); | ||
| 131 | + verify(moduleMapper).insert(captor.capture()); | ||
| 132 | + assertThat(captor.getValue().getSCreatedBy()).isEqualTo("ALICE"); | ||
| 133 | + } | ||
| 134 | + | ||
| 85 | private CreateModuleDTO baseDto() { | 135 | private CreateModuleDTO baseDto() { |
| 86 | CreateModuleDTO dto = new CreateModuleDTO(); | 136 | CreateModuleDTO dto = new CreateModuleDTO(); |
| 87 | dto.setSDisplayType("手机端"); | 137 | dto.setSDisplayType("手机端"); |