Commit bf2370ba1158d83515f157eabcf9a9a3ebcb0b21

Authored by zichun
1 parent b8957829

feat(mod): module delete service + soft delete REQ-MOD-003

backend/src/main/java/com/xly/erp/module/mod/service/ModuleService.java
@@ -7,4 +7,6 @@ public interface ModuleService { @@ -7,4 +7,6 @@ public interface ModuleService {
7 Integer create(CreateModuleDTO dto); 7 Integer create(CreateModuleDTO dto);
8 8
9 Integer update(Integer id, UpdateModuleDTO dto); 9 Integer update(Integer id, UpdateModuleDTO dto);
  10 +
  11 + void delete(Integer id);
10 } 12 }
backend/src/main/java/com/xly/erp/module/mod/service/impl/ModuleServiceImpl.java
@@ -93,6 +93,25 @@ public class ModuleServiceImpl implements ModuleService { @@ -93,6 +93,25 @@ public class ModuleServiceImpl implements ModuleService {
93 return id; 93 return id;
94 } 94 }
95 95
  96 + @Override
  97 + public void delete(Integer id) {
  98 + Module original = moduleMapper.selectById(id);
  99 + if (original == null || Boolean.TRUE.equals(original.getBDeleted())) {
  100 + throw new BizException(40400, "模块不存在或已删除");
  101 + }
  102 + if (moduleMapper.hasActiveChildren(id)) {
  103 + throw new BizException(40901, "模块仍有未删除子节点");
  104 + }
  105 +
  106 + Module entity = new Module();
  107 + entity.setIIncrement(id);
  108 + entity.setBDeleted(true);
  109 + entity.setTDeletedDate(LocalDateTime.now());
  110 + String authedUserNo = SecurityContextHelper.currentUserNo();
  111 + entity.setSDeletedBy(authedUserNo != null ? authedUserNo : stub.getStubUserNo());
  112 + moduleMapper.updateById(entity);
  113 + }
  114 +
96 private void validateParent(Integer id, Integer parentId) { 115 private void validateParent(Integer id, Integer parentId) {
97 if (parentId == null) { 116 if (parentId == null) {
98 return; 117 return;
backend/src/test/java/com/xly/erp/module/mod/service/ModuleServiceImplTest.java
@@ -238,6 +238,74 @@ class ModuleServiceImplTest { @@ -238,6 +238,74 @@ class ModuleServiceImplTest {
238 verify(moduleMapper, never()).updateById(any(Module.class)); 238 verify(moduleMapper, never()).updateById(any(Module.class));
239 } 239 }
240 240
  241 + @Test
  242 + void deleteWithValidId_softDeletes_andSetsAuditFields() {
  243 + when(moduleMapper.selectById(10)).thenReturn(stubExistingModule(10));
  244 + when(moduleMapper.hasActiveChildren(10)).thenReturn(false);
  245 + when(moduleMapper.updateById(any(Module.class))).thenReturn(1);
  246 +
  247 + service.delete(10);
  248 +
  249 + ArgumentCaptor<Module> captor = ArgumentCaptor.forClass(Module.class);
  250 + verify(moduleMapper).updateById(captor.capture());
  251 + Module passed = captor.getValue();
  252 + assertThat(passed.getIIncrement()).isEqualTo(10);
  253 + assertThat(passed.getBDeleted()).isTrue();
  254 + assertThat(passed.getTDeletedDate()).isNotNull();
  255 + assertThat(passed.getSDeletedBy()).isEqualTo("STUB_ADMIN");
  256 + assertThat(passed.getSProcedureName()).isNull();
  257 + assertThat(passed.getSCreatedBy()).isNull();
  258 + assertThat(passed.getSBrandsId()).isNull();
  259 + }
  260 +
  261 + @Test
  262 + void deleteWithTargetNotFound_throws40400() {
  263 + when(moduleMapper.selectById(99)).thenReturn(null);
  264 +
  265 + assertThatThrownBy(() -> service.delete(99))
  266 + .isInstanceOf(BizException.class)
  267 + .hasFieldOrPropertyWithValue("code", 40400);
  268 + verify(moduleMapper, never()).updateById(any(Module.class));
  269 + }
  270 +
  271 + @Test
  272 + void deleteWithTargetAlreadyDeleted_throws40400() {
  273 + Module deleted = stubExistingModule(10);
  274 + deleted.setBDeleted(true);
  275 + when(moduleMapper.selectById(10)).thenReturn(deleted);
  276 +
  277 + assertThatThrownBy(() -> service.delete(10))
  278 + .isInstanceOf(BizException.class)
  279 + .hasFieldOrPropertyWithValue("code", 40400);
  280 + verify(moduleMapper, never()).updateById(any(Module.class));
  281 + }
  282 +
  283 + @Test
  284 + void deleteWithActiveChildren_throws40901() {
  285 + when(moduleMapper.selectById(10)).thenReturn(stubExistingModule(10));
  286 + when(moduleMapper.hasActiveChildren(10)).thenReturn(true);
  287 +
  288 + assertThatThrownBy(() -> service.delete(10))
  289 + .isInstanceOf(BizException.class)
  290 + .hasFieldOrPropertyWithValue("code", 40901);
  291 + verify(moduleMapper, never()).updateById(any(Module.class));
  292 + }
  293 +
  294 + @Test
  295 + void deleteSetsDeletedByFromAuthenticatedUser() {
  296 + SecurityContextHolder.getContext().setAuthentication(
  297 + new UsernamePasswordAuthenticationToken("BOB", null, Collections.emptyList()));
  298 + when(moduleMapper.selectById(10)).thenReturn(stubExistingModule(10));
  299 + when(moduleMapper.hasActiveChildren(10)).thenReturn(false);
  300 + when(moduleMapper.updateById(any(Module.class))).thenReturn(1);
  301 +
  302 + service.delete(10);
  303 +
  304 + ArgumentCaptor<Module> captor = ArgumentCaptor.forClass(Module.class);
  305 + verify(moduleMapper).updateById(captor.capture());
  306 + assertThat(captor.getValue().getSDeletedBy()).isEqualTo("BOB");
  307 + }
  308 +
241 private UpdateModuleDTO baseUpdateDto() { 309 private UpdateModuleDTO baseUpdateDto() {
242 UpdateModuleDTO dto = new UpdateModuleDTO(); 310 UpdateModuleDTO dto = new UpdateModuleDTO();
243 dto.setSDisplayType("手机端"); 311 dto.setSDisplayType("手机端");