MerchantSubaccountApplicationServiceTest.java 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242
  1. package com.ruoyi.app.user;
  2. import com.ruoyi.app.user.dto.MerchantSubaccountCreateRequest;
  3. import com.ruoyi.app.user.dto.StoreAccountsView;
  4. import com.ruoyi.common.exception.ServiceException;
  5. import com.ruoyi.common.utils.MessageUtils;
  6. import com.ruoyi.system.domain.InfoUser;
  7. import com.ruoyi.system.domain.PosStore;
  8. import com.ruoyi.system.mapper.PosStoreMapper;
  9. import com.ruoyi.system.service.IInfoUserService;
  10. import com.ruoyi.system.service.IMerchantSubaccountStoreService;
  11. import com.ruoyi.system.service.MerchantStoreAccessService;
  12. import org.junit.jupiter.api.Test;
  13. import org.mockito.ArgumentCaptor;
  14. import org.mockito.MockedStatic;
  15. import java.util.List;
  16. import java.util.Set;
  17. import static org.junit.jupiter.api.Assertions.assertEquals;
  18. import static org.junit.jupiter.api.Assertions.assertNull;
  19. import static org.junit.jupiter.api.Assertions.assertThrows;
  20. import static org.mockito.ArgumentMatchers.any;
  21. import static org.mockito.ArgumentMatchers.anyString;
  22. import static org.mockito.Mockito.doAnswer;
  23. import static org.mockito.Mockito.mock;
  24. import static org.mockito.Mockito.mockStatic;
  25. import static org.mockito.Mockito.verify;
  26. import static org.mockito.Mockito.when;
  27. class MerchantSubaccountApplicationServiceTest {
  28. @Test
  29. void newSubaccountUsesTelPhoneAsTheBusinessPhoneField() {
  30. IInfoUserService infoUserService = mock(IInfoUserService.class);
  31. IMerchantSubaccountStoreService relationService = mock(IMerchantSubaccountStoreService.class);
  32. MerchantStoreAccessService accessService = mock(MerchantStoreAccessService.class);
  33. PosStoreMapper posStoreMapper = mock(PosStoreMapper.class);
  34. MerchantTokenSessionService tokenSessionService = mock(MerchantTokenSessionService.class);
  35. BusinessPhoneService businessPhoneService = mock(BusinessPhoneService.class);
  36. MerchantSubaccountApplicationService service = new MerchantSubaccountApplicationService(
  37. infoUserService, relationService, accessService, posStoreMapper,
  38. tokenSessionService, businessPhoneService);
  39. when(accessService.getAccessibleStoreIds(10L)).thenReturn(Set.of(7L));
  40. when(infoUserService.getinfouserName("0912345678")).thenReturn(null);
  41. doAnswer(invocation -> {
  42. InfoUser user = invocation.getArgument(0);
  43. user.setUserId(20L);
  44. return 1;
  45. }).when(infoUserService).insertInfoUser(any(InfoUser.class));
  46. when(relationService.selectStoreIdsBySubaccountUserId(20L)).thenReturn(List.of());
  47. MerchantSubaccountCreateRequest request = new MerchantSubaccountCreateRequest();
  48. request.setPhone("0912345678");
  49. request.setUserName("store_staff");
  50. request.setName("分店账号");
  51. request.setPassword("password");
  52. request.setStoreIds(List.of(7L));
  53. var created = service.create(10L, request);
  54. assertEquals("store_staff", created.getUserName());
  55. ArgumentCaptor<InfoUser> captor = ArgumentCaptor.forClass(InfoUser.class);
  56. verify(infoUserService).insertInfoUser(captor.capture());
  57. assertEquals("store_staff", captor.getValue().getUserName());
  58. assertEquals("0912345678", captor.getValue().getTelPhone());
  59. assertNull(captor.getValue().getPhone());
  60. verify(businessPhoneService).ensureUnique("0912345678", null);
  61. }
  62. @Test
  63. void listStoreAccountsRejectsMissingOrDeletedStore() {
  64. PosStoreMapper posStoreMapper = mock(PosStoreMapper.class);
  65. MerchantSubaccountApplicationService service = newService(posStoreMapper);
  66. when(posStoreMapper.selectPosStoreById(7L)).thenReturn(null);
  67. PosStore deleted = new PosStore();
  68. deleted.setDelFlag("1");
  69. when(posStoreMapper.selectPosStoreById(8L)).thenReturn(deleted);
  70. try (MockedStatic<MessageUtils> messages = mockStatic(MessageUtils.class)) {
  71. messages.when(() -> MessageUtils.message(anyString()))
  72. .thenAnswer(invocation -> invocation.getArgument(0));
  73. ServiceException missing = assertThrows(ServiceException.class,
  74. () -> service.listStoreAccounts(7L));
  75. assertEquals("merchant.store.not.found", missing.getMessage());
  76. ServiceException deletedStore = assertThrows(ServiceException.class,
  77. () -> service.listStoreAccounts(8L));
  78. assertEquals("merchant.store.not.found", deletedStore.getMessage());
  79. }
  80. }
  81. @Test
  82. void listStoreAccountsReturnsOwnerAndEligibleSubaccountsWithContactFields() {
  83. IInfoUserService infoUserService = mock(IInfoUserService.class);
  84. IMerchantSubaccountStoreService relationService = mock(IMerchantSubaccountStoreService.class);
  85. PosStoreMapper posStoreMapper = mock(PosStoreMapper.class);
  86. MerchantSubaccountApplicationService service = newService(infoUserService, relationService, posStoreMapper);
  87. PosStore store = new PosStore();
  88. store.setDelFlag("0");
  89. store.setUserId(10L);
  90. when(posStoreMapper.selectPosStoreById(7L)).thenReturn(store);
  91. when(infoUserService.selectInfoUserByUserId(10L)).thenReturn(contactUser(10L, "1", "0"));
  92. when(relationService.selectEligibleSubaccountsByStoreId(7L))
  93. .thenReturn(List.of(contactUser(20L, "5", "0")));
  94. StoreAccountsView view = service.listStoreAccounts(7L);
  95. assertEquals(10L, view.getOwner().getUserId());
  96. assertEquals("1", view.getOwner().getUserType());
  97. assertEquals("nick-10", view.getOwner().getNickName());
  98. assertEquals("tel-10", view.getOwner().getPhone());
  99. assertEquals("avatar-10", view.getOwner().getAvatar());
  100. assertEquals("imKey-10", view.getOwner().getImApiKey());
  101. assertEquals("900010", view.getOwner().getImUserId());
  102. assertEquals("cid-10", view.getOwner().getCid());
  103. assertEquals("ios", view.getOwner().getCidType());
  104. assertEquals("device-10", view.getOwner().getDeviceToken());
  105. assertEquals("voip-10", view.getOwner().getVoIPToken());
  106. assertEquals(1, view.getSubaccounts().size());
  107. assertEquals(20L, view.getSubaccounts().get(0).getUserId());
  108. assertEquals("5", view.getSubaccounts().get(0).getUserType());
  109. assertEquals("nick-20", view.getSubaccounts().get(0).getNickName());
  110. }
  111. @Test
  112. void listStoreAccountsOmitsUnavailableOwner() {
  113. IInfoUserService infoUserService = mock(IInfoUserService.class);
  114. IMerchantSubaccountStoreService relationService = mock(IMerchantSubaccountStoreService.class);
  115. PosStoreMapper posStoreMapper = mock(PosStoreMapper.class);
  116. MerchantSubaccountApplicationService service = newService(infoUserService, relationService, posStoreMapper);
  117. PosStore store = new PosStore();
  118. store.setDelFlag("0");
  119. store.setUserId(10L);
  120. when(posStoreMapper.selectPosStoreById(7L)).thenReturn(store);
  121. when(infoUserService.selectInfoUserByUserId(10L)).thenReturn(contactUser(10L, "1", "1"));
  122. when(relationService.selectEligibleSubaccountsByStoreId(7L)).thenReturn(List.of());
  123. StoreAccountsView view = service.listStoreAccounts(7L);
  124. assertNull(view.getOwner());
  125. assertEquals(List.of(), view.getSubaccounts());
  126. }
  127. private MerchantSubaccountApplicationService newService(PosStoreMapper posStoreMapper) {
  128. return newService(mock(IInfoUserService.class), mock(IMerchantSubaccountStoreService.class), posStoreMapper);
  129. }
  130. private MerchantSubaccountApplicationService newService(IInfoUserService infoUserService,
  131. IMerchantSubaccountStoreService relationService,
  132. PosStoreMapper posStoreMapper) {
  133. return new MerchantSubaccountApplicationService(infoUserService, relationService,
  134. mock(MerchantStoreAccessService.class), posStoreMapper,
  135. mock(MerchantTokenSessionService.class), mock(BusinessPhoneService.class));
  136. }
  137. private InfoUser contactUser(Long userId, String userType, String status) {
  138. InfoUser user = new InfoUser();
  139. user.setUserId(userId);
  140. user.setUserType(userType);
  141. user.setStatus(status);
  142. user.setDelFlag("0");
  143. user.setNickName("nick-" + userId);
  144. user.setTelPhone("tel-" + userId);
  145. user.setAvatar("avatar-" + userId);
  146. user.setImApiKey("imKey-" + userId);
  147. user.setImUserId(900000L + userId);
  148. user.setCid("cid-" + userId);
  149. user.setCidType("ios");
  150. user.setDeviceToken("device-" + userId);
  151. user.setVoIPToken("voip-" + userId);
  152. return user;
  153. }
  154. @Test
  155. void missingUsernameDoesNotFallBackToPhone() {
  156. var fixture = new UsernameFixture();
  157. fixture.request.setUserName(" ");
  158. try (MockedStatic<MessageUtils> messages = mockStatic(MessageUtils.class)) {
  159. messages.when(() -> MessageUtils.message(anyString())).thenAnswer(i -> i.getArgument(0));
  160. assertEquals("merchant.subaccount.username.required", assertThrows(ServiceException.class,
  161. () -> fixture.service.create(10L, fixture.request)).getMessage());
  162. }
  163. org.mockito.Mockito.verify(fixture.users, org.mockito.Mockito.never()).insertInfoUser(any());
  164. }
  165. @Test
  166. void usernameCannotCollideWithAnotherAccount() {
  167. var fixture = new UsernameFixture();
  168. InfoUser other = new InfoUser(); other.setUserId(99L);
  169. when(fixture.users.getinfouserName("staff")).thenReturn(other);
  170. try (MockedStatic<MessageUtils> messages = mockStatic(MessageUtils.class)) {
  171. messages.when(() -> MessageUtils.message(anyString())).thenAnswer(i -> i.getArgument(0));
  172. assertEquals("merchant.subaccount.username.exists", assertThrows(ServiceException.class,
  173. () -> fixture.service.create(10L, fixture.request)).getMessage());
  174. }
  175. }
  176. @Test
  177. void renameExistingSubaccountPreservesContactAndRevokesSessions() {
  178. var fixture = new UsernameFixture();
  179. var request = new com.ruoyi.app.user.dto.MerchantSubaccountUpdateRequest();
  180. request.setUserName(" new_staff "); request.setStoreIds(List.of(7L));
  181. var view = fixture.service.update(10L, 20L, request);
  182. assertEquals("new_staff", view.getUserName());
  183. assertEquals("0912345678", view.getPhone());
  184. ArgumentCaptor<InfoUser> update = ArgumentCaptor.forClass(InfoUser.class);
  185. verify(fixture.users).updateInfoUser(update.capture());
  186. assertEquals("new_staff", update.getValue().getUserName());
  187. assertNull(update.getValue().getTelPhone());
  188. verify(fixture.sessions).revokeAll(20L);
  189. }
  190. @Test
  191. void unchangedUsernameCanBelongToSelfWithoutRevokingSessions() {
  192. var fixture = new UsernameFixture();
  193. when(fixture.users.getinfouserName("0912345678")).thenReturn(fixture.target);
  194. var request = new com.ruoyi.app.user.dto.MerchantSubaccountUpdateRequest();
  195. request.setUserName("0912345678"); request.setStoreIds(List.of(7L));
  196. assertEquals("0912345678", fixture.service.update(10L, 20L, request).getUserName());
  197. org.mockito.Mockito.verify(fixture.sessions, org.mockito.Mockito.never()).revokeAll(20L);
  198. }
  199. private static class UsernameFixture {
  200. final IInfoUserService users = mock(IInfoUserService.class);
  201. final MerchantTokenSessionService sessions = mock(MerchantTokenSessionService.class);
  202. final InfoUser target = new InfoUser();
  203. final MerchantSubaccountCreateRequest request = new MerchantSubaccountCreateRequest();
  204. final MerchantSubaccountApplicationService service;
  205. UsernameFixture() {
  206. var access = mock(MerchantStoreAccessService.class);
  207. var relations = mock(IMerchantSubaccountStoreService.class);
  208. service = new MerchantSubaccountApplicationService(users, relations, access,
  209. mock(PosStoreMapper.class), sessions, mock(BusinessPhoneService.class));
  210. when(access.getAccessibleStoreIds(10L)).thenReturn(Set.of(7L));
  211. target.setUserId(20L); target.setUserType("5"); target.setDelFlag("0");
  212. target.setMerchantOwnerId(10L); target.setUserName("0912345678"); target.setTelPhone("0912345678");
  213. when(users.selectInfoUserByUserId(20L)).thenReturn(target);
  214. when(users.updateInfoUser(any())).thenReturn(1);
  215. request.setUserName("staff"); request.setPhone("0912345678");
  216. request.setPassword("encrypted-password"); request.setStoreIds(List.of(7L));
  217. }
  218. }
  219. }