Commit a75b8d36742b9d287da3694f542e937beb2c1089

Authored by zichun
1 parent 36c5912f

feat(usr): user update dto + service happy path REQ-USR-002

backend/src/main/java/com/xly/erp/module/usr/dto/UpdateUserDTO.java 0 → 100644
  1 +package com.xly.erp.module.usr.dto;
  2 +
  3 +import com.fasterxml.jackson.annotation.JsonProperty;
  4 +import jakarta.validation.constraints.NotBlank;
  5 +import jakarta.validation.constraints.Size;
  6 +
  7 +import java.util.List;
  8 +
  9 +public class UpdateUserDTO {
  10 +
  11 + @JsonProperty("sUserNo")
  12 + @NotBlank
  13 + @Size(max = 50)
  14 + private String sUserNo;
  15 +
  16 + @JsonProperty("sUserName")
  17 + @NotBlank
  18 + @Size(max = 50)
  19 + private String sUserName;
  20 +
  21 + @JsonProperty("iStaffId")
  22 + private Integer iStaffId;
  23 +
  24 + @JsonProperty("sUserType")
  25 + @NotBlank
  26 + private String sUserType;
  27 +
  28 + @JsonProperty("sLanguage")
  29 + @NotBlank
  30 + private String sLanguage;
  31 +
  32 + @JsonProperty("bCanModifyDocs")
  33 + private Boolean bCanModifyDocs;
  34 +
  35 + @JsonProperty("permissionCategoryIds")
  36 + private List<Integer> permissionCategoryIds;
  37 +
  38 + public String getSUserNo() { return sUserNo; }
  39 + public void setSUserNo(String sUserNo) { this.sUserNo = sUserNo; }
  40 + public String getSUserName() { return sUserName; }
  41 + public void setSUserName(String sUserName) { this.sUserName = sUserName; }
  42 + public Integer getIStaffId() { return iStaffId; }
  43 + public void setIStaffId(Integer iStaffId) { this.iStaffId = iStaffId; }
  44 + public String getSUserType() { return sUserType; }
  45 + public void setSUserType(String sUserType) { this.sUserType = sUserType; }
  46 + public String getSLanguage() { return sLanguage; }
  47 + public void setSLanguage(String sLanguage) { this.sLanguage = sLanguage; }
  48 + public Boolean getBCanModifyDocs() { return bCanModifyDocs; }
  49 + public void setBCanModifyDocs(Boolean bCanModifyDocs) { this.bCanModifyDocs = bCanModifyDocs; }
  50 + public List<Integer> getPermissionCategoryIds() { return permissionCategoryIds; }
  51 + public void setPermissionCategoryIds(List<Integer> permissionCategoryIds) { this.permissionCategoryIds = permissionCategoryIds; }
  52 +}
backend/src/main/java/com/xly/erp/module/usr/service/UserService.java
1 package com.xly.erp.module.usr.service; 1 package com.xly.erp.module.usr.service;
2 2
3 import com.xly.erp.module.usr.dto.CreateUserDTO; 3 import com.xly.erp.module.usr.dto.CreateUserDTO;
  4 +import com.xly.erp.module.usr.dto.UpdateUserDTO;
4 5
5 import java.util.Map; 6 import java.util.Map;
6 7
7 public interface UserService { 8 public interface UserService {
8 Map<String, Object> create(CreateUserDTO dto); 9 Map<String, Object> create(CreateUserDTO dto);
  10 +
  11 + Integer update(Integer id, UpdateUserDTO dto);
9 } 12 }
backend/src/main/java/com/xly/erp/module/usr/service/impl/UserServiceImpl.java
@@ -5,6 +5,7 @@ import com.xly.erp.common.config.TenantProperties; @@ -5,6 +5,7 @@ import com.xly.erp.common.config.TenantProperties;
5 import com.xly.erp.common.exception.BizException; 5 import com.xly.erp.common.exception.BizException;
6 import com.xly.erp.common.security.SecurityContextHelper; 6 import com.xly.erp.common.security.SecurityContextHelper;
7 import com.xly.erp.module.usr.dto.CreateUserDTO; 7 import com.xly.erp.module.usr.dto.CreateUserDTO;
  8 +import com.xly.erp.module.usr.dto.UpdateUserDTO;
8 import com.xly.erp.module.usr.entity.User; 9 import com.xly.erp.module.usr.entity.User;
9 import com.xly.erp.module.usr.entity.UserPermission; 10 import com.xly.erp.module.usr.entity.UserPermission;
10 import com.xly.erp.module.usr.mapper.PermissionCategoryMapper; 11 import com.xly.erp.module.usr.mapper.PermissionCategoryMapper;
@@ -114,4 +115,60 @@ public class UserServiceImpl implements UserService { @@ -114,4 +115,60 @@ public class UserServiceImpl implements UserService {
114 result.put("sUserNo", entity.getSUserNo()); 115 result.put("sUserNo", entity.getSUserNo());
115 return result; 116 return result;
116 } 117 }
  118 +
  119 + @Override
  120 + public Integer update(Integer id, UpdateUserDTO dto) {
  121 + User original = userMapper.selectById(id);
  122 + if (original == null || Boolean.TRUE.equals(original.getBDeleted())) {
  123 + throw new BizException(40400, "用户不存在或已删除");
  124 + }
  125 + if (!USER_TYPES.contains(dto.getSUserType())) {
  126 + throw new BizException(40001, "sUserType: 取值非法");
  127 + }
  128 + if (!LANGUAGES.contains(dto.getSLanguage())) {
  129 + throw new BizException(40001, "sLanguage: 取值非法");
  130 + }
  131 + if (dto.getIStaffId() != null && !staffMapper.existsActiveById(dto.getIStaffId())) {
  132 + throw new BizException(40022, "职员不存在或已删除");
  133 + }
  134 + List<Integer> ids = dto.getPermissionCategoryIds();
  135 + if (ids != null && !ids.isEmpty()) {
  136 + int found = permissionCategoryMapper.countActiveByIds(ids);
  137 + if (found != ids.size()) {
  138 + throw new BizException(40023, "权限分类含无效 id");
  139 + }
  140 + }
  141 +
  142 + User entity = new User();
  143 + entity.setIIncrement(id);
  144 + entity.setSUserNo(dto.getSUserNo());
  145 + entity.setSUserName(dto.getSUserName());
  146 + entity.setIStaffId(dto.getIStaffId());
  147 + entity.setSUserType(dto.getSUserType());
  148 + entity.setSLanguage(dto.getSLanguage());
  149 + entity.setBCanModifyDocs(dto.getBCanModifyDocs() != null ? dto.getBCanModifyDocs() : false);
  150 + try {
  151 + userMapper.updateById(entity);
  152 + } catch (DuplicateKeyException e) {
  153 + throw new BizException(40020, "用户号或用户名已存在");
  154 + }
  155 +
  156 + userPermissionMapper.deleteByUserId(id);
  157 + if (ids != null && !ids.isEmpty()) {
  158 + String authedUserNo = SecurityContextHelper.currentUserNo();
  159 + String createdBy = authedUserNo != null ? authedUserNo : stub.getStubUserNo();
  160 + LocalDateTime now = LocalDateTime.now();
  161 + for (Integer cid : ids) {
  162 + UserPermission rel = new UserPermission();
  163 + rel.setSBrandsId(tenant.getBrandsId());
  164 + rel.setSSubsidiaryId(tenant.getSubsidiaryId());
  165 + rel.setTCreateDate(now);
  166 + rel.setIUserId(id);
  167 + rel.setICategoryId(cid);
  168 + rel.setSCreatedBy(createdBy);
  169 + userPermissionMapper.insert(rel);
  170 + }
  171 + }
  172 + return id;
  173 + }
117 } 174 }
backend/src/test/java/com/xly/erp/module/usr/service/UserServiceImplTest.java
@@ -4,6 +4,7 @@ import com.xly.erp.common.config.StubSecurityProperties; @@ -4,6 +4,7 @@ import com.xly.erp.common.config.StubSecurityProperties;
4 import com.xly.erp.common.config.TenantProperties; 4 import com.xly.erp.common.config.TenantProperties;
5 import com.xly.erp.common.exception.BizException; 5 import com.xly.erp.common.exception.BizException;
6 import com.xly.erp.module.usr.dto.CreateUserDTO; 6 import com.xly.erp.module.usr.dto.CreateUserDTO;
  7 +import com.xly.erp.module.usr.dto.UpdateUserDTO;
7 import com.xly.erp.module.usr.entity.User; 8 import com.xly.erp.module.usr.entity.User;
8 import com.xly.erp.module.usr.entity.UserPermission; 9 import com.xly.erp.module.usr.entity.UserPermission;
9 import com.xly.erp.module.usr.mapper.PermissionCategoryMapper; 10 import com.xly.erp.module.usr.mapper.PermissionCategoryMapper;
@@ -180,6 +181,92 @@ class UserServiceImplTest { @@ -180,6 +181,92 @@ class UserServiceImplTest {
180 assertThat(cap.getValue().getSCreatedBy()).isEqualTo("ALICE"); 181 assertThat(cap.getValue().getSCreatedBy()).isEqualTo("ALICE");
181 } 182 }
182 183
  184 + @Test
  185 + void updateWithValidDto_invokesUpdateById_andRebuildsPermissions() {
  186 + when(userMapper.selectById(10)).thenReturn(stubExistingUser(10));
  187 + when(staffMapper.existsActiveById(7)).thenReturn(true);
  188 + when(permissionCategoryMapper.countActiveByIds(List.of(11, 22))).thenReturn(2);
  189 + when(userMapper.updateById(any(User.class))).thenReturn(1);
  190 + when(userPermissionMapper.deleteByUserId(10)).thenReturn(3);
  191 +
  192 + UpdateUserDTO dto = baseUpdateDto();
  193 + dto.setIStaffId(7);
  194 + dto.setPermissionCategoryIds(List.of(11, 22));
  195 +
  196 + Integer result = service.update(10, dto);
  197 +
  198 + assertThat(result).isEqualTo(10);
  199 + ArgumentCaptor<User> uc = ArgumentCaptor.forClass(User.class);
  200 + verify(userMapper).updateById(uc.capture());
  201 + User passed = uc.getValue();
  202 + assertThat(passed.getIIncrement()).isEqualTo(10);
  203 + assertThat(passed.getSUserNo()).isEqualTo("u_new");
  204 + assertThat(passed.getSPasswordHash()).isNull();
  205 + assertThat(passed.getSCreatedBy()).isNull();
  206 + assertThat(passed.getTCreateDate()).isNull();
  207 + assertThat(passed.getSBrandsId()).isNull();
  208 +
  209 + verify(userPermissionMapper, times(1)).deleteByUserId(10);
  210 + verify(userPermissionMapper, times(2)).insert(any(UserPermission.class));
  211 + }
  212 +
  213 + @Test
  214 + void updateWithTargetNotFound_throws40400() {
  215 + when(userMapper.selectById(99)).thenReturn(null);
  216 + assertThatThrownBy(() -> service.update(99, baseUpdateDto()))
  217 + .isInstanceOf(BizException.class)
  218 + .hasFieldOrPropertyWithValue("code", 40400);
  219 + verify(userMapper, never()).updateById(any(User.class));
  220 + }
  221 +
  222 + @Test
  223 + void updateWithTargetAlreadyDeleted_throws40400() {
  224 + User deleted = stubExistingUser(10);
  225 + deleted.setBDeleted(true);
  226 + when(userMapper.selectById(10)).thenReturn(deleted);
  227 + assertThatThrownBy(() -> service.update(10, baseUpdateDto()))
  228 + .isInstanceOf(BizException.class)
  229 + .hasFieldOrPropertyWithValue("code", 40400);
  230 + verify(userMapper, never()).updateById(any(User.class));
  231 + }
  232 +
  233 + @Test
  234 + void updateWithBCanModifyDocsNull_setsFalseInEntity() {
  235 + when(userMapper.selectById(10)).thenReturn(stubExistingUser(10));
  236 + when(userMapper.updateById(any(User.class))).thenReturn(1);
  237 + UpdateUserDTO dto = baseUpdateDto();
  238 + dto.setBCanModifyDocs(null);
  239 +
  240 + service.update(10, dto);
  241 +
  242 + ArgumentCaptor<User> uc = ArgumentCaptor.forClass(User.class);
  243 + verify(userMapper).updateById(uc.capture());
  244 + assertThat(uc.getValue().getBCanModifyDocs()).isFalse();
  245 + }
  246 +
  247 + private UpdateUserDTO baseUpdateDto() {
  248 + UpdateUserDTO dto = new UpdateUserDTO();
  249 + dto.setSUserNo("u_new");
  250 + dto.setSUserName("用户新");
  251 + dto.setSUserType("普通用户");
  252 + dto.setSLanguage("zh");
  253 + dto.setBCanModifyDocs(false);
  254 + return dto;
  255 + }
  256 +
  257 + private User stubExistingUser(Integer id) {
  258 + User u = new User();
  259 + u.setIIncrement(id);
  260 + u.setSUserNo("u_orig");
  261 + u.setSUserName("原用户");
  262 + u.setSUserType("普通用户");
  263 + u.setSLanguage("zh");
  264 + u.setSPasswordHash("$2a$10$origHash");
  265 + u.setSCreatedBy("ORIG_USER");
  266 + u.setBDeleted(false);
  267 + return u;
  268 + }
  269 +
183 private CreateUserDTO baseDto() { 270 private CreateUserDTO baseDto() {
184 CreateUserDTO dto = new CreateUserDTO(); 271 CreateUserDTO dto = new CreateUserDTO();
185 dto.setSUserNo("u001"); 272 dto.setSUserNo("u001");