Commit 13500fafe38ebc601d2933104d0e244cb80b3bcb

Authored by zichun
1 parent 26bef0e5

feat(usr): 修改用户主记录部分更新与存在性校验 REQ-USR-002

backend/src/main/java/com/xly/erp/modules/usr/service/UsrUserService.java
1 1 package com.xly.erp.modules.usr.service;
2 2  
3 3 import com.xly.erp.modules.usr.dto.CreateUserDTO;
  4 +import com.xly.erp.modules.usr.dto.UpdateUserDTO;
4 5  
5 6 /**
6   - * 用户业务服务(docs/04 § 1.2)。REQ-USR-001
  7 + * 用户业务服务(docs/04 § 1.2)。REQ-USR-001 / REQ-USR-002
7 8 */
8 9 public interface UsrUserService {
9 10  
... ... @@ -15,4 +16,16 @@ public interface UsrUserService {
15 16 * @return 新建用户主键 iIncrement
16 17 */
17 18 Integer createUser(CreateUserDTO dto);
  19 +
  20 + /**
  21 + * 修改用户(REQ-USR-002):校验目标用户存在 → 校验关联职员 / 权限存在 →
  22 + * 按"部分更新(null 不改)"语义更新 {@code usr_user} 主记录(不动 sUserName /
  23 + * sPassword / 审计列 / 租户列)→ 按"全量覆盖"语义重写该用户在 {@code usr_user_permission}
  24 + * 的授权。整体单事务。
  25 + *
  26 + * @param id 目标用户主键 iIncrement
  27 + * @param dto 修改用户入参
  28 + * @return 被修改用户主键 iIncrement(等于入参 id)
  29 + */
  30 + Integer updateUser(Integer id, UpdateUserDTO dto);
18 31 }
... ...
backend/src/main/java/com/xly/erp/modules/usr/service/impl/UsrUserServiceImpl.java
... ... @@ -5,6 +5,7 @@ import com.xly.erp.common.exception.BusinessException;
5 5 import com.xly.erp.common.response.ResultCode;
6 6 import com.xly.erp.common.security.SecurityUtil;
7 7 import com.xly.erp.modules.usr.dto.CreateUserDTO;
  8 +import com.xly.erp.modules.usr.dto.UpdateUserDTO;
8 9 import com.xly.erp.modules.usr.entity.UsrUser;
9 10 import com.xly.erp.modules.usr.entity.UsrUserPermission;
10 11 import com.xly.erp.modules.usr.mapper.UsrEmployeeMapper;
... ... @@ -129,4 +130,37 @@ public class UsrUserServiceImpl implements UsrUserService {
129 130  
130 131 return newUserId;
131 132 }
  133 +
  134 + @Override
  135 + @Transactional(rollbackFor = Exception.class)
  136 + public Integer updateUser(Integer id, UpdateUserDTO dto) {
  137 + // 1. 目标用户存在性校验(不存在 → 40401,不写入任何表)。
  138 + UsrUser existing = usrUserMapper.selectById(id);
  139 + if (existing == null) {
  140 + throw new BusinessException(ResultCode.NOT_FOUND);
  141 + }
  142 +
  143 + // 2. 组装目标实体:仅 set 主键 + 非 null 可更新列。
  144 + // 不 set sUserName / sPassword / sCreator / tCreateDate / 租户列,
  145 + // 依赖 MP updateById「null 字段不参与 SET」语义保持原值不被覆盖。
  146 + UsrUser target = new UsrUser();
  147 + target.setIIncrement(id);
  148 + target.setSUserType(dto.getSUserType());
  149 + target.setSLanguage(dto.getSLanguage());
  150 + if (dto.getSUserNo() != null) {
  151 + target.setSUserNo(dto.getSUserNo());
  152 + }
  153 + if (dto.getIEmployeeId() != null) {
  154 + target.setIEmployeeId(dto.getIEmployeeId());
  155 + }
  156 + if (dto.getICanModifyBill() != null) {
  157 + target.setICanModifyBill(dto.getICanModifyBill());
  158 + }
  159 + if (dto.getIIsVoid() != null) {
  160 + target.setIIsVoid(dto.getIIsVoid());
  161 + }
  162 + usrUserMapper.updateById(target);
  163 +
  164 + return id;
  165 + }
132 166 }
... ...
backend/src/test/java/com/xly/erp/modules/usr/service/UsrUserServiceImplTest.java
... ... @@ -14,6 +14,7 @@ import com.xly.erp.common.exception.BusinessException;
14 14 import com.xly.erp.common.response.ResultCode;
15 15 import com.xly.erp.common.security.SecurityUtil;
16 16 import com.xly.erp.modules.usr.dto.CreateUserDTO;
  17 +import com.xly.erp.modules.usr.dto.UpdateUserDTO;
17 18 import com.xly.erp.modules.usr.entity.UsrEmployee;
18 19 import com.xly.erp.modules.usr.entity.UsrPermission;
19 20 import com.xly.erp.modules.usr.entity.UsrUser;
... ... @@ -201,4 +202,76 @@ class UsrUserServiceImplTest {
201 202 assertThat(service.createUser(dto)).isEqualTo(303);
202 203 verify(usrEmployeeMapper).selectById(7);
203 204 }
  205 +
  206 + // ---------------- REQ-USR-002 T2:目标用户存在性 + 主记录部分更新 ----------------
  207 +
  208 + private UpdateUserDTO minimalUpdateDto() {
  209 + UpdateUserDTO dto = new UpdateUserDTO();
  210 + dto.setSUserType("普通用户");
  211 + dto.setSLanguage("中文");
  212 + return dto;
  213 + }
  214 +
  215 + @Test
  216 + void updateNonExistentUserThrows40401() {
  217 + when(usrUserMapper.selectById(404)).thenReturn(null);
  218 +
  219 + assertThatThrownBy(() -> service.updateUser(404, minimalUpdateDto()))
  220 + .isInstanceOf(BusinessException.class)
  221 + .extracting(e -> ((BusinessException) e).getResultCode())
  222 + .isEqualTo(ResultCode.NOT_FOUND);
  223 + verify(usrUserMapper, never()).updateById(any(UsrUser.class));
  224 + verify(usrUserPermissionMapper, never()).delete(any(Wrapper.class));
  225 + verify(usrUserPermissionMapper, never()).insert(any(UsrUserPermission.class));
  226 + }
  227 +
  228 + @Test
  229 + void updateAppliesNonNullColumnsAndKeepsIdentityImmutable() {
  230 + when(usrUserMapper.selectById(55)).thenReturn(new UsrUser());
  231 + when(usrUserMapper.updateById(any(UsrUser.class))).thenReturn(1);
  232 + UpdateUserDTO dto = new UpdateUserDTO();
  233 + dto.setSUserType("超级管理员");
  234 + dto.setSLanguage("英文");
  235 + dto.setICanModifyBill(1);
  236 + dto.setIIsVoid(1);
  237 + dto.setSUserNo("N9");
  238 +
  239 + Integer returned = service.updateUser(55, dto);
  240 +
  241 + assertThat(returned).isEqualTo(55);
  242 + ArgumentCaptor<UsrUser> captor = ArgumentCaptor.forClass(UsrUser.class);
  243 + verify(usrUserMapper).updateById(captor.capture());
  244 + UsrUser saved = captor.getValue();
  245 + assertThat(saved.getIIncrement()).isEqualTo(55);
  246 + assertThat(saved.getSUserType()).isEqualTo("超级管理员");
  247 + assertThat(saved.getSLanguage()).isEqualTo("英文");
  248 + assertThat(saved.getICanModifyBill()).isEqualTo(1);
  249 + assertThat(saved.getIIsVoid()).isEqualTo(1);
  250 + assertThat(saved.getSUserNo()).isEqualTo("N9");
  251 + // 身份 / 密码 / 审计列不参与 SET(保持 null,依赖 MP null 不更新语义)。
  252 + assertThat(saved.getSUserName()).isNull();
  253 + assertThat(saved.getSPassword()).isNull();
  254 + assertThat(saved.getSCreator()).isNull();
  255 + assertThat(saved.getTCreateDate()).isNull();
  256 + }
  257 +
  258 + @Test
  259 + void nullOptionalColumnsAreNotOverwritten() {
  260 + when(usrUserMapper.selectById(77)).thenReturn(new UsrUser());
  261 + when(usrUserMapper.updateById(any(UsrUser.class))).thenReturn(1);
  262 +
  263 + service.updateUser(77, minimalUpdateDto());
  264 +
  265 + ArgumentCaptor<UsrUser> captor = ArgumentCaptor.forClass(UsrUser.class);
  266 + verify(usrUserMapper).updateById(captor.capture());
  267 + UsrUser saved = captor.getValue();
  268 + assertThat(saved.getIIncrement()).isEqualTo(77);
  269 + assertThat(saved.getSUserType()).isEqualTo("普通用户");
  270 + assertThat(saved.getSLanguage()).isEqualTo("中文");
  271 + // 可选列 DTO 为 null → 实体保持 null,MP 不 SET。
  272 + assertThat(saved.getSUserNo()).isNull();
  273 + assertThat(saved.getIEmployeeId()).isNull();
  274 + assertThat(saved.getICanModifyBill()).isNull();
  275 + assertThat(saved.getIIsVoid()).isNull();
  276 + }
204 277 }
... ...