Переглянути джерело

fix(guide): confirmBind 重绑时复位 status 为 binding,修复解绑后无法重新绑定

iwt 1 день тому
батько
коміт
c8dd1b4b6d

+ 5 - 3
cfc-backend/src/main/java/com/etotem/cfc/service/GuideFamilyService.java

@@ -81,11 +81,13 @@ public class GuideFamilyService {
             gf = new GuideFamily();
             gf.setGuideId(guideId);
             gf.setFamilyId(familyId);
-            gf.setStatus("binding");
-            gf.setBoundAt(new Date());
             gf.setCreatedAt(new Date());
         }
-        
+        // 无论新建还是命中已有行(含 status='cancelled' 的历史解绑记录),
+        // 都必须复位为 binding,否则 isBound() 永远返回 false,重绑形同虚设。
+        gf.setStatus("binding");
+        gf.setBoundAt(new Date());
+
         gf.setServiceType(serviceType);
         gf.setServicePrice(servicePrice);
         gf.setUpdatedAt(new Date());

+ 81 - 0
cfc-backend/src/test/java/com/etotem/cfc/unit/GuideFamilyServiceBindTest.java

@@ -0,0 +1,81 @@
+package com.etotem.cfc.unit;
+
+import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
+import com.etotem.cfc.entity.GuideFamily;
+import com.etotem.cfc.mapper.GuideFamilyMapper;
+import com.etotem.cfc.service.GuideFamilyService;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+
+import java.lang.reflect.Field;
+
+import static org.junit.jupiter.api.Assertions.*;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.Mockito.*;
+
+class GuideFamilyServiceBindTest {
+
+    private GuideFamilyService service;
+    private GuideFamilyMapper mapper;
+
+    @BeforeEach
+    void setUp() throws Exception {
+        service = new GuideFamilyService();
+        mapper = mock(GuideFamilyMapper.class);
+        Field f = GuideFamilyService.class.getDeclaredField("guideFamilyMapper");
+        f.setAccessible(true);
+        f.set(service, mapper);
+    }
+
+    @Test
+    void 重绑时应复活status为binding() {
+        GuideFamily cancelled = new GuideFamily();
+        cancelled.setId(7L);
+        cancelled.setGuideId(1L);
+        cancelled.setFamilyId(10L);
+        cancelled.setStatus("cancelled");
+
+        // 第 1 次 selectOne:查是否已绑定其他规划师 -> null
+        // 第 2 次 selectOne:查本规划师已有记录 -> cancelled 行
+        when(mapper.selectOne(any(QueryWrapper.class))).thenReturn(null).thenReturn(cancelled);
+        when(mapper.updateById(any(GuideFamily.class))).thenReturn(1);
+
+        boolean ok = service.confirmBind(1L, 10L, "paid", 199);
+
+        assertTrue(ok);
+        assertEquals("binding", cancelled.getStatus(), "重绑必须把 status 复位为 binding");
+        assertNotNull(cancelled.getBoundAt(), "重绑必须刷新 boundAt");
+        verify(mapper).updateById(cancelled);
+        verify(mapper, never()).insert(any(GuideFamily.class));
+    }
+
+    @Test
+    void 首次绑定应插入新行且status为binding() {
+        when(mapper.selectOne(any(QueryWrapper.class))).thenReturn(null);
+        when(mapper.insert(any(GuideFamily.class))).thenReturn(1);
+
+        boolean ok = service.confirmBind(1L, 10L, "free", 0);
+
+        assertTrue(ok);
+        verify(mapper).insert(argThat(g ->
+                "binding".equals(g.getStatus())
+                        && Long.valueOf(1L).equals(g.getGuideId())
+                        && Long.valueOf(10L).equals(g.getFamilyId())
+                        && g.getBoundAt() != null));
+    }
+
+    @Test
+    void 家庭已绑定他人应抛异常() {
+        GuideFamily other = new GuideFamily();
+        other.setGuideId(2L);
+        other.setFamilyId(10L);
+        other.setStatus("binding");
+        when(mapper.selectOne(any(QueryWrapper.class))).thenReturn(other);
+
+        RuntimeException ex = assertThrows(RuntimeException.class,
+                () -> service.confirmBind(1L, 10L, "paid", 100));
+        assertTrue(ex.getMessage().contains("已绑定其他成长规划师"));
+        verify(mapper, never()).insert(any(GuideFamily.class));
+        verify(mapper, never()).updateById(any(GuideFamily.class));
+    }
+}