Эх сурвалжийг харах

feat(backend): 新增家庭成员时按POPULATION规则发放人口券(成员有账号发自己,无账号发家庭创建者)

Xiaogang Liao 1 сар өмнө
parent
commit
8606f32026

+ 16 - 0
cfc-backend/src/main/java/com/etotem/cfc/service/FamilyMemberService.java

@@ -58,6 +58,9 @@ public class FamilyMemberService {
     @Resource
     private FamilyMemberLogMapper familyMemberLogMapper;
 
+    @Resource
+    private CouponService couponService;
+
     /**
      * 添加家庭成员
      */
@@ -148,6 +151,19 @@ public class FamilyMemberService {
         // 为新成员创建与所有现有成员的双向关系
         familyRelationshipService.createRelationsForNewMember(familyId, member.getId(), genLevel.getOffset());
 
+        // 发放家庭人口券(POPULATION):有账号发到成员自己,无账号发到家庭创建者
+        try {
+            Long targetUserId = member.getUserId();
+            if (targetUserId == null) {
+                targetUserId = user.getFamilyId() != null
+                        ? familyMapper.selectById(user.getFamilyId()).getCreatorId()
+                        : userId;
+            }
+            couponService.grantPopulationCoupons(targetUserId, member.getId());
+        } catch (Exception e) {
+            log.error("发放家庭人口券异常: memberId={}", member.getId(), e);
+        }
+
         return toFamilyMemberVO(member);
     }
 

+ 121 - 0
cfc-backend/src/test/java/com/etotem/cfc/service/FamilyMemberServiceCouponTest.java

@@ -0,0 +1,121 @@
+package com.etotem.cfc.service;
+
+import com.etotem.cfc.dto.AddFamilyMemberDTO;
+import com.etotem.cfc.entity.Family;
+import com.etotem.cfc.entity.FamilyMember;
+import com.etotem.cfc.entity.User;
+import com.etotem.cfc.mapper.FamilyMapper;
+import com.etotem.cfc.mapper.FamilyMemberLogMapper;
+import com.etotem.cfc.mapper.FamilyMemberMapper;
+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 static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertNotNull;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.doAnswer;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+/**
+ * FamilyMemberService.addMember POPULATION 发券单元测试(无 SpringBootTest,避免 MySQL 连接)
+ * - 成员有账号(手机号匹配):券发到成员自己账户
+ * - 成员无账号:券发到家庭创建者账户
+ */
+public class FamilyMemberServiceCouponTest {
+
+    @Mock
+    private FamilyMemberMapper familyMemberMapper;
+
+    @Mock
+    private UserMapper userMapper;
+
+    @Mock
+    private FamilyMapper familyMapper;
+
+    @Mock
+    private FamilyMemberLogMapper familyMemberLogMapper;
+
+    @Mock
+    private FamilyRelationshipService familyRelationshipService;
+
+    @Mock
+    private SystemConfigService systemConfigService;
+
+    @Mock
+    private CouponService couponService;
+
+    @InjectMocks
+    private FamilyMemberService familyMemberService;
+
+    @BeforeEach
+    public void setup() {
+        MockitoAnnotations.openMocks(this);
+    }
+
+    private User user(Long id, Long familyId) {
+        User u = new User();
+        u.setId(id);
+        u.setFamilyId(familyId);
+        return u;
+    }
+
+    private AddFamilyMemberDTO dto(String nickname, String phone) {
+        AddFamilyMemberDTO d = new AddFamilyMemberDTO();
+        d.setNickname(nickname);
+        d.setGenerationLevel("child");
+        d.setPhone(phone);
+        return d;
+    }
+
+    private void stubInsertBackfillsId(Long memberId) {
+        doAnswer(inv -> {
+            FamilyMember m = inv.getArgument(0);
+            m.setId(memberId);
+            return 1;
+        }).when(familyMemberMapper).insert(any(FamilyMember.class));
+    }
+
+    @Test
+    public void addMember_withMatchedUser_grantsCouponToMemberSelf() {
+        when(userMapper.selectById(1001L)).thenReturn(user(1001L, 3001L));
+        User matchedUser = user(5001L, 3001L);
+        when(userMapper.selectOne(any())).thenReturn(matchedUser);
+        stubInsertBackfillsId(2001L);
+
+        familyMemberService.addMember(1001L, dto("王小明", "13800000000"));
+
+        verify(couponService).grantPopulationCoupons(eq(5001L), eq(2001L));
+    }
+
+    @Test
+    public void addMember_withoutPhone_grantsCouponToFamilyCreator() {
+        when(userMapper.selectById(1001L)).thenReturn(user(1001L, 3001L));
+        Family family = new Family();
+        family.setId(3001L);
+        family.setCreatorId(1001L);
+        when(familyMapper.selectById(3001L)).thenReturn(family);
+        stubInsertBackfillsId(2001L);
+
+        familyMemberService.addMember(1001L, dto("王小明", null));
+
+        verify(couponService).grantPopulationCoupons(eq(1001L), eq(2001L));
+    }
+
+    @Test
+    public void addMember_returnsMemberVO() {
+        when(userMapper.selectById(1001L)).thenReturn(user(1001L, 3001L));
+        stubInsertBackfillsId(2001L);
+
+        com.etotem.cfc.dto.FamilyMemberVO vo = familyMemberService.addMember(1001L, dto("王小明", null));
+
+        assertNotNull(vo);
+        assertEquals(Long.valueOf(2001L), vo.getId());
+        assertEquals("王小明", vo.getNickname());
+    }
+}