|
|
@@ -0,0 +1,190 @@
|
|
|
+package com.etotem.cfc.unit;
|
|
|
+
|
|
|
+import com.etotem.cfc.common.Result;
|
|
|
+import com.etotem.cfc.entity.DistributionRelation;
|
|
|
+import com.etotem.cfc.entity.DistributionSystem;
|
|
|
+import com.etotem.cfc.mapper.DistributionRelationMapper;
|
|
|
+import com.etotem.cfc.mapper.DistributionSystemMapper;
|
|
|
+import com.etotem.cfc.mapper.UserMapper;
|
|
|
+import com.etotem.cfc.service.DistributionService;
|
|
|
+import org.junit.jupiter.api.BeforeEach;
|
|
|
+import org.junit.jupiter.api.Test;
|
|
|
+import org.mockito.ArgumentCaptor;
|
|
|
+
|
|
|
+import java.lang.reflect.Field;
|
|
|
+import java.util.Collections;
|
|
|
+import java.util.Map;
|
|
|
+
|
|
|
+import static org.junit.jupiter.api.Assertions.*;
|
|
|
+import static org.mockito.ArgumentMatchers.any;
|
|
|
+import static org.mockito.Mockito.*;
|
|
|
+
|
|
|
+/**
|
|
|
+ * T37 销售体系结算唯一负责人口径(gap C2)单元测试。
|
|
|
+ *
|
|
|
+ * <p>覆盖:ownerId 作为唯一结算对象(settleToUserId)、金额=佣金总额(settleAmount=totalCommission)、
|
|
|
+ * ownerId 为空降级取体系树 root 节点用户、无负责人走「无团队结算」分支、
|
|
|
+ * 旧 70/30 拆分字段一期置 null、体系不可用/订单金额不合法错误分支、updateSystem 透传 ownerId。</p>
|
|
|
+ */
|
|
|
+class DistributionServiceUnitTest {
|
|
|
+
|
|
|
+ private DistributionService service;
|
|
|
+ private DistributionSystemMapper systemMapper;
|
|
|
+ private DistributionRelationMapper relationMapper;
|
|
|
+ private UserMapper userMapper;
|
|
|
+
|
|
|
+ @BeforeEach
|
|
|
+ void setUp() throws Exception {
|
|
|
+ service = new DistributionService();
|
|
|
+ systemMapper = mock(DistributionSystemMapper.class);
|
|
|
+ relationMapper = mock(DistributionRelationMapper.class);
|
|
|
+ userMapper = mock(UserMapper.class);
|
|
|
+ inject(service, "distributionSystemMapper", systemMapper);
|
|
|
+ inject(service, "distributionRelationMapper", relationMapper);
|
|
|
+ inject(service, "userMapper", userMapper);
|
|
|
+ }
|
|
|
+
|
|
|
+ /** 系统启用 + ownerId 非空:结算对象 = ownerId,金额 = 佣金总额,旧字段置 null,不再查关系表 */
|
|
|
+ @Test
|
|
|
+ void calculateCommission_ownerId非空_结算给负责人且金额为佣金总额() {
|
|
|
+ DistributionSystem system = new DistributionSystem();
|
|
|
+ system.setId(1L);
|
|
|
+ system.setOwnerId(100L);
|
|
|
+ system.setProfitRate(50); // 千分比
|
|
|
+ system.setEnabled(true);
|
|
|
+ when(systemMapper.selectById(1L)).thenReturn(system);
|
|
|
+
|
|
|
+ // 订单 20000 分,佣金 = 20000*50/1000 = 1000 分
|
|
|
+ Result<Map<String, Object>> result = service.calculateCommission(1L, 999L, 20000);
|
|
|
+
|
|
|
+ assertEquals(200, result.getCode());
|
|
|
+ Map<String, Object> data = result.getData();
|
|
|
+ assertEquals(1000, data.get("totalCommission"));
|
|
|
+ assertEquals(100L, data.get("settleToUserId"));
|
|
|
+ assertEquals(1000, data.get("settleAmount"));
|
|
|
+ // 旧 70/30 拆分字段一期置 null
|
|
|
+ assertNull(data.get("level1Amount"));
|
|
|
+ assertNull(data.get("level1User"));
|
|
|
+ assertNull(data.get("level2Amount"));
|
|
|
+ assertNull(data.get("level2User"));
|
|
|
+ assertNull(data.get("platformAmount"));
|
|
|
+ // ownerId 存在时不再查询关系表
|
|
|
+ verify(relationMapper, never()).selectList(any());
|
|
|
+ }
|
|
|
+
|
|
|
+ /** ownerId 为空:降级取体系树 root 节点(parentId=null)用户作为结算对象 */
|
|
|
+ @Test
|
|
|
+ void calculateCommission_ownerId为空_降级取树root节点用户() {
|
|
|
+ DistributionSystem system = new DistributionSystem();
|
|
|
+ system.setId(1L);
|
|
|
+ system.setOwnerId(null);
|
|
|
+ system.setProfitRate(50);
|
|
|
+ system.setEnabled(true);
|
|
|
+ when(systemMapper.selectById(1L)).thenReturn(system);
|
|
|
+
|
|
|
+ DistributionRelation root = new DistributionRelation();
|
|
|
+ root.setId(10L);
|
|
|
+ root.setSystemId(1L);
|
|
|
+ root.setUserId(200L);
|
|
|
+ root.setParentId(null);
|
|
|
+ root.setDepth(0);
|
|
|
+ when(relationMapper.selectList(any())).thenReturn(Collections.singletonList(root));
|
|
|
+
|
|
|
+ Result<Map<String, Object>> result = service.calculateCommission(1L, 999L, 20000);
|
|
|
+
|
|
|
+ assertEquals(200, result.getCode());
|
|
|
+ Map<String, Object> data = result.getData();
|
|
|
+ assertEquals(1000, data.get("totalCommission"));
|
|
|
+ assertEquals(200L, data.get("settleToUserId"));
|
|
|
+ assertEquals(1000, data.get("settleAmount"));
|
|
|
+ }
|
|
|
+
|
|
|
+ /** ownerId 为空且树无 root 节点:走「无团队结算」分支(settleToUserId=null,settleAmount=0) */
|
|
|
+ @Test
|
|
|
+ void calculateCommission_无负责人_走无团队结算分支() {
|
|
|
+ DistributionSystem system = new DistributionSystem();
|
|
|
+ system.setId(1L);
|
|
|
+ system.setOwnerId(null);
|
|
|
+ system.setProfitRate(50);
|
|
|
+ system.setEnabled(true);
|
|
|
+ when(systemMapper.selectById(1L)).thenReturn(system);
|
|
|
+ when(relationMapper.selectList(any())).thenReturn(Collections.emptyList());
|
|
|
+
|
|
|
+ Result<Map<String, Object>> result = service.calculateCommission(1L, 999L, 20000);
|
|
|
+
|
|
|
+ assertEquals(200, result.getCode());
|
|
|
+ Map<String, Object> data = result.getData();
|
|
|
+ assertEquals(1000, data.get("totalCommission"));
|
|
|
+ assertNull(data.get("settleToUserId"));
|
|
|
+ assertEquals(0, data.get("settleAmount"));
|
|
|
+ }
|
|
|
+
|
|
|
+ /** 体系禁用:返回「销售体系不可用」,不结算 */
|
|
|
+ @Test
|
|
|
+ void calculateCommission_体系禁用_返回不可用() {
|
|
|
+ DistributionSystem system = new DistributionSystem();
|
|
|
+ system.setId(1L);
|
|
|
+ system.setEnabled(false);
|
|
|
+ when(systemMapper.selectById(1L)).thenReturn(system);
|
|
|
+
|
|
|
+ Result<Map<String, Object>> result = service.calculateCommission(1L, 999L, 20000);
|
|
|
+
|
|
|
+ assertEquals(500, result.getCode());
|
|
|
+ assertEquals("销售体系不可用", result.getMessage());
|
|
|
+ verify(relationMapper, never()).selectList(any());
|
|
|
+ }
|
|
|
+
|
|
|
+ /** 订单金额为空:返回「订单金额不合法」,不结算 */
|
|
|
+ @Test
|
|
|
+ void calculateCommission_订单金额为空_返回不合法() {
|
|
|
+ DistributionSystem system = new DistributionSystem();
|
|
|
+ system.setId(1L);
|
|
|
+ system.setEnabled(true);
|
|
|
+ when(systemMapper.selectById(1L)).thenReturn(system);
|
|
|
+
|
|
|
+ Result<Map<String, Object>> result = service.calculateCommission(1L, 999L, null);
|
|
|
+
|
|
|
+ assertEquals(500, result.getCode());
|
|
|
+ assertEquals("订单金额不合法", result.getMessage());
|
|
|
+ }
|
|
|
+
|
|
|
+ /** updateSystem 透传 ownerId:传入 ownerId 时更新既有体系负责人 */
|
|
|
+ @Test
|
|
|
+ void updateSystem_传入ownerId_更新负责人() {
|
|
|
+ DistributionSystem existing = new DistributionSystem();
|
|
|
+ existing.setId(1L);
|
|
|
+ existing.setName("旧体系");
|
|
|
+ existing.setOwnerId(null);
|
|
|
+ existing.setProfitRate(30);
|
|
|
+ when(systemMapper.selectById(1L)).thenReturn(existing);
|
|
|
+ when(systemMapper.updateById(any(DistributionSystem.class))).thenReturn(1);
|
|
|
+
|
|
|
+ DistributionSystem incoming = new DistributionSystem();
|
|
|
+ incoming.setId(1L);
|
|
|
+ incoming.setOwnerId(555L); // 仅改负责人
|
|
|
+
|
|
|
+ Result<String> result = service.updateSystem(incoming);
|
|
|
+
|
|
|
+ assertEquals(200, result.getCode());
|
|
|
+ ArgumentCaptor<DistributionSystem> captor = ArgumentCaptor.forClass(DistributionSystem.class);
|
|
|
+ verify(systemMapper).updateById(captor.capture());
|
|
|
+ DistributionSystem updated = captor.getValue();
|
|
|
+ assertEquals(555L, updated.getOwnerId());
|
|
|
+ assertEquals("旧体系", updated.getName()); // 未传入的字段保持不变
|
|
|
+ }
|
|
|
+
|
|
|
+ private static void inject(Object target, String fieldName, Object value) throws Exception {
|
|
|
+ Class<?> type = target.getClass();
|
|
|
+ while (type != null) {
|
|
|
+ try {
|
|
|
+ Field f = type.getDeclaredField(fieldName);
|
|
|
+ f.setAccessible(true);
|
|
|
+ f.set(target, value);
|
|
|
+ return;
|
|
|
+ } catch (NoSuchFieldException e) {
|
|
|
+ type = type.getSuperclass();
|
|
|
+ }
|
|
|
+ }
|
|
|
+ throw new NoSuchFieldException(fieldName);
|
|
|
+ }
|
|
|
+}
|