|
|
@@ -0,0 +1,176 @@
|
|
|
+package com.etotem.cfc.service;
|
|
|
+
|
|
|
+import com.etotem.cfc.entity.Family;
|
|
|
+import com.etotem.cfc.entity.FamilyJoinRequest;
|
|
|
+import com.etotem.cfc.entity.User;
|
|
|
+import com.etotem.cfc.mapper.FamilyJoinRequestMapper;
|
|
|
+import com.etotem.cfc.mapper.FamilyMapper;
|
|
|
+import com.etotem.cfc.mapper.UserMapper;
|
|
|
+import org.junit.jupiter.api.BeforeEach;
|
|
|
+import org.junit.jupiter.api.Test;
|
|
|
+import org.mockito.InjectMocks;
|
|
|
+import org.mockito.Mock;
|
|
|
+import org.mockito.MockitoAnnotations;
|
|
|
+
|
|
|
+import java.util.HashMap;
|
|
|
+import java.util.Map;
|
|
|
+
|
|
|
+import static org.junit.jupiter.api.Assertions.assertEquals;
|
|
|
+import static org.mockito.ArgumentMatchers.any;
|
|
|
+import static org.mockito.Mockito.never;
|
|
|
+import static org.mockito.Mockito.verify;
|
|
|
+import static org.mockito.Mockito.when;
|
|
|
+
|
|
|
+/**
|
|
|
+ * 家庭加入审批通过时的平台推荐人绑定规则测试(需求):
|
|
|
+ * 1. 未注册/无推荐人用户被邀请加入家庭 → 绑定为邀请人的上级推荐人(requester.referrerId = inviter.referrerId)
|
|
|
+ * 2. 已注册用户无推荐人 → 同样绑定为邀请人的上级推荐人
|
|
|
+ * 3. 已注册用户已有推荐人 → 不动(不调用绑定)
|
|
|
+ * 4. 短码路径(无邀请人 inviterUserId=null)→ 不处理
|
|
|
+ * 5. 邀请人自身无推荐人 → 不处理(被邀请者保持无推荐人)
|
|
|
+ *
|
|
|
+ * 仅 token 路径(FamilyJoinRequest.inviterUserId 非空)会绑定;
|
|
|
+ * 幂等由 CommissionService.bindReferrerByUserId 保证(已有推荐人直接忽略)。
|
|
|
+ */
|
|
|
+class FamilyJoinRequestServiceReferrerBindTest {
|
|
|
+
|
|
|
+ @Mock
|
|
|
+ private FamilyJoinRequestMapper familyJoinRequestMapper;
|
|
|
+
|
|
|
+ @Mock
|
|
|
+ private FamilyMapper familyMapper;
|
|
|
+
|
|
|
+ @Mock
|
|
|
+ private UserMapper userMapper;
|
|
|
+
|
|
|
+ @Mock
|
|
|
+ private FamilyInvitationService familyInvitationService;
|
|
|
+
|
|
|
+ @Mock
|
|
|
+ private UnlockGateService unlockGateService;
|
|
|
+
|
|
|
+ @Mock
|
|
|
+ private CommissionService commissionService;
|
|
|
+
|
|
|
+ @InjectMocks
|
|
|
+ private FamilyJoinRequestService service;
|
|
|
+
|
|
|
+ private Map<Long, User> userDb;
|
|
|
+
|
|
|
+ @BeforeEach
|
|
|
+ void setUp() {
|
|
|
+ MockitoAnnotations.openMocks(this);
|
|
|
+ userDb = new HashMap<>();
|
|
|
+ }
|
|
|
+
|
|
|
+ // ==================== 用例 1:新用户(无推荐人)→ 绑定为邀请人的推荐人 ====================
|
|
|
+
|
|
|
+ @Test
|
|
|
+ void approve_tokenPath_newUserWithoutReferrer_bindsInviterReferrer() {
|
|
|
+ FamilyJoinRequest request = pendingRequest(1L, 3L, 100L, 2L, "by_token");
|
|
|
+ User requester = user(3L, null, null); // 未注册(无推荐人、未加入家庭)
|
|
|
+ User approver = user(2L, 100L, 9L); // 审批人 = 邀请人,其上级推荐人为 9
|
|
|
+ stubApprovalFlow(request, requester, approver, approver);
|
|
|
+
|
|
|
+ service.approveJoinRequest(1L, 2L, "");
|
|
|
+
|
|
|
+ verify(commissionService).bindReferrerByUserId(3L, 9L);
|
|
|
+ assertEquals(100L, requester.getFamilyId()); // 同时被加入家庭
|
|
|
+ }
|
|
|
+
|
|
|
+ // ==================== 用例 2:已注册用户(无推荐人)→ 绑定为邀请人的推荐人 ====================
|
|
|
+
|
|
|
+ @Test
|
|
|
+ void approve_tokenPath_registeredUserWithoutReferrer_bindsInviterReferrer() {
|
|
|
+ FamilyJoinRequest request = pendingRequest(1L, 3L, 100L, 2L, "by_token");
|
|
|
+ User requester = user(3L, 50L, null); // 已注册、已在其他家庭(走合并分支)、无推荐人
|
|
|
+ User approver = user(2L, 100L, 9L);
|
|
|
+ stubApprovalFlow(request, requester, approver, approver);
|
|
|
+
|
|
|
+ service.approveJoinRequest(1L, 2L, "");
|
|
|
+
|
|
|
+ verify(commissionService).bindReferrerByUserId(3L, 9L);
|
|
|
+ }
|
|
|
+
|
|
|
+ // ==================== 用例 3:已注册用户已有推荐人 → 不动 ====================
|
|
|
+
|
|
|
+ @Test
|
|
|
+ void approve_tokenPath_userWithReferrer_doesNotRebind() {
|
|
|
+ FamilyJoinRequest request = pendingRequest(1L, 3L, 100L, 2L, "by_token");
|
|
|
+ User requester = user(3L, null, 8L); // 已有推荐人 8
|
|
|
+ User approver = user(2L, 100L, 9L);
|
|
|
+ stubApprovalFlow(request, requester, approver, approver);
|
|
|
+
|
|
|
+ service.approveJoinRequest(1L, 2L, "");
|
|
|
+
|
|
|
+ verify(commissionService, never()).bindReferrerByUserId(any(), any());
|
|
|
+ }
|
|
|
+
|
|
|
+ // ==================== 用例 4:短码路径(无邀请人)→ 不处理 ====================
|
|
|
+
|
|
|
+ @Test
|
|
|
+ void approve_shortCodePath_noInviter_doesNotBind() {
|
|
|
+ FamilyJoinRequest request = pendingRequest(1L, 3L, 100L, null, "by_code");
|
|
|
+ User requester = user(3L, null, null);
|
|
|
+ User approver = user(2L, 100L, 9L);
|
|
|
+ approver.setIsFamilyAdmin(true); // 短码路径回退家庭管理员审批
|
|
|
+ stubApprovalFlow(request, requester, approver, null);
|
|
|
+
|
|
|
+ service.approveJoinRequest(1L, 2L, "");
|
|
|
+
|
|
|
+ verify(commissionService, never()).bindReferrerByUserId(any(), any());
|
|
|
+ }
|
|
|
+
|
|
|
+ // ==================== 用例 5:邀请人自身无推荐人 → 不处理 ====================
|
|
|
+
|
|
|
+ @Test
|
|
|
+ void approve_inviterWithoutReferrer_doesNotBind() {
|
|
|
+ FamilyJoinRequest request = pendingRequest(1L, 3L, 100L, 2L, "by_token");
|
|
|
+ User requester = user(3L, null, null);
|
|
|
+ User approver = user(2L, 100L, null); // 邀请人自身没有推荐人
|
|
|
+ stubApprovalFlow(request, requester, approver, approver);
|
|
|
+
|
|
|
+ service.approveJoinRequest(1L, 2L, "");
|
|
|
+
|
|
|
+ verify(commissionService, never()).bindReferrerByUserId(any(), any());
|
|
|
+ assertEquals(null, requester.getReferrerId()); // 被邀请者保持无推荐人
|
|
|
+ }
|
|
|
+
|
|
|
+ // ==================== 辅助构造 ====================
|
|
|
+
|
|
|
+ private FamilyJoinRequest pendingRequest(Long id, Long requesterId, Long familyId, Long inviterId, String method) {
|
|
|
+ FamilyJoinRequest r = new FamilyJoinRequest();
|
|
|
+ r.setId(id);
|
|
|
+ r.setRequesterUserId(requesterId);
|
|
|
+ r.setTargetFamilyId(familyId);
|
|
|
+ r.setInviterUserId(inviterId);
|
|
|
+ r.setJoinMethod(method);
|
|
|
+ r.setStatus("pending");
|
|
|
+ return r;
|
|
|
+ }
|
|
|
+
|
|
|
+ private User user(Long id, Long familyId, Long referrerId) {
|
|
|
+ User u = new User();
|
|
|
+ u.setId(id);
|
|
|
+ u.setFamilyId(familyId);
|
|
|
+ u.setReferrerId(referrerId);
|
|
|
+ return u;
|
|
|
+ }
|
|
|
+
|
|
|
+ private void stubApprovalFlow(FamilyJoinRequest request, User requester, User approver, User inviter) {
|
|
|
+ Family family = new Family();
|
|
|
+ family.setId(request.getTargetFamilyId());
|
|
|
+ family.setName("测试家庭");
|
|
|
+
|
|
|
+ when(familyJoinRequestMapper.selectById(request.getId())).thenReturn(request);
|
|
|
+ when(familyMapper.selectById(request.getTargetFamilyId())).thenReturn(family);
|
|
|
+
|
|
|
+ approver.setFamilyId(request.getTargetFamilyId()); // 审批人是目标家庭成员
|
|
|
+ userDb.put(approver.getId(), approver);
|
|
|
+ userDb.put(requester.getId(), requester);
|
|
|
+ if (inviter != null) {
|
|
|
+ userDb.put(inviter.getId(), inviter);
|
|
|
+ }
|
|
|
+ when(userMapper.selectById(any(Long.class))).thenAnswer(inv -> userDb.get(inv.getArgument(0)));
|
|
|
+ }
|
|
|
+}
|