- 添加数据库迁移脚本,为 play_clerk_level_info 表新增 order_number 字段 - 更新测试数据种子,设置默认等级的排序号 - 新增店员用户API测试,验证按等级排序号和在线状态的排序逻辑
This commit is contained in:
@@ -0,0 +1,322 @@
|
||||
package com.starry.admin.api;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
|
||||
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post;
|
||||
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath;
|
||||
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
|
||||
|
||||
import com.fasterxml.jackson.databind.JsonNode;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import com.fasterxml.jackson.databind.node.ObjectNode;
|
||||
import com.starry.admin.modules.clerk.module.entity.PlayClerkLevelInfoEntity;
|
||||
import com.starry.admin.modules.clerk.module.entity.PlayClerkUserInfoEntity;
|
||||
import com.starry.admin.modules.clerk.service.IPlayClerkLevelInfoService;
|
||||
import com.starry.admin.modules.clerk.service.IPlayClerkUserInfoService;
|
||||
import com.starry.admin.utils.SecurityUtils;
|
||||
import com.starry.common.utils.IdUtils;
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.ThreadLocalRandom;
|
||||
import org.junit.jupiter.api.AfterEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.test.web.servlet.MvcResult;
|
||||
|
||||
class PlayClerkUserInfoApiTest extends AbstractApiTest {
|
||||
|
||||
private final ObjectMapper objectMapper = new ObjectMapper();
|
||||
|
||||
@Autowired
|
||||
private IPlayClerkLevelInfoService clerkLevelInfoService;
|
||||
|
||||
@Autowired
|
||||
private IPlayClerkUserInfoService clerkUserInfoService;
|
||||
|
||||
private final List<String> levelIdsToCleanup = new ArrayList<>();
|
||||
private final List<String> clerkIdsToCleanup = new ArrayList<>();
|
||||
|
||||
@AfterEach
|
||||
void tearDown() {
|
||||
ensureTenantContext();
|
||||
if (!clerkIdsToCleanup.isEmpty()) {
|
||||
clerkUserInfoService.removeByIds(clerkIdsToCleanup);
|
||||
clerkIdsToCleanup.clear();
|
||||
}
|
||||
if (!levelIdsToCleanup.isEmpty()) {
|
||||
clerkLevelInfoService.removeByIds(levelIdsToCleanup);
|
||||
levelIdsToCleanup.clear();
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
// 场景:不同等级的排序号不同,接口应按照排序号升序返回,验证等级排序字段生效。
|
||||
void listOrdersByLevelOrderNumberAscending() throws Exception {
|
||||
ensureTenantContext();
|
||||
PlayClerkLevelInfoEntity lowOrderLevel = createClerkLevel("low", 1L, 50);
|
||||
PlayClerkLevelInfoEntity highOrderLevel = createClerkLevel("high", 5L, 60);
|
||||
|
||||
String filterToken = "order-sort-" + IdUtils.getUuid().substring(0, 8);
|
||||
String lowOrderClerkId = createClerk(filterToken + "-low", lowOrderLevel.getId(), "0");
|
||||
String highOrderClerkId = createClerk(filterToken + "-high", highOrderLevel.getId(), "1");
|
||||
|
||||
MvcResult result = mockMvc.perform(get("/clerk/user/list")
|
||||
.param("pageNum", "1")
|
||||
.param("pageSize", "20")
|
||||
.param("nickname", filterToken)
|
||||
.header(TENANT_HEADER, DEFAULT_TENANT)
|
||||
.header(USER_HEADER, DEFAULT_USER))
|
||||
.andExpect(status().isOk())
|
||||
.andReturn();
|
||||
|
||||
String responseBody = result.getResponse().getContentAsString();
|
||||
JsonNode root = objectMapper.readTree(responseBody);
|
||||
assertThat(root.get("code").asInt()).isEqualTo(200);
|
||||
JsonNode records = root.path("data");
|
||||
assertThat(records.isArray()).as("Response payload: %s", responseBody).isTrue();
|
||||
|
||||
List<String> orderedIds = new ArrayList<>();
|
||||
for (JsonNode record : records) {
|
||||
orderedIds.add(record.path("id").asText());
|
||||
}
|
||||
|
||||
assertThat(orderedIds).contains(lowOrderClerkId, highOrderClerkId);
|
||||
assertThat(orderedIds.indexOf(lowOrderClerkId))
|
||||
.withFailMessage("Unexpected order for token %s: %s", filterToken, orderedIds)
|
||||
.isLessThan(orderedIds.indexOf(highOrderClerkId));
|
||||
}
|
||||
|
||||
@Test
|
||||
// 场景:相同等级排序号相同,接口应按在线状态优先展示在线店员,验证排序二级规则。
|
||||
void listOrdersByOnlineStateWhenOrderNumberMatches() throws Exception {
|
||||
ensureTenantContext();
|
||||
PlayClerkLevelInfoEntity level = createClerkLevel("tie", 3L, 70);
|
||||
|
||||
String filterToken = "online-priority-" + IdUtils.getUuid().substring(0, 8);
|
||||
String onlineClerkId = createClerk(filterToken + "-online", level.getId(), "1");
|
||||
String offlineClerkId = createClerk(filterToken + "-offline", level.getId(), "0");
|
||||
|
||||
MvcResult result = mockMvc.perform(get("/clerk/user/list")
|
||||
.param("pageNum", "1")
|
||||
.param("pageSize", "20")
|
||||
.param("nickname", filterToken)
|
||||
.header(TENANT_HEADER, DEFAULT_TENANT)
|
||||
.header(USER_HEADER, DEFAULT_USER))
|
||||
.andExpect(status().isOk())
|
||||
.andReturn();
|
||||
|
||||
String responseBody = result.getResponse().getContentAsString();
|
||||
JsonNode root = objectMapper.readTree(responseBody);
|
||||
assertThat(root.get("code").asInt()).isEqualTo(200);
|
||||
JsonNode records = root.path("data");
|
||||
assertThat(records.isArray()).as("Response payload: %s", responseBody).isTrue();
|
||||
|
||||
List<String> orderedIds = new ArrayList<>();
|
||||
for (JsonNode record : records) {
|
||||
orderedIds.add(record.path("id").asText());
|
||||
}
|
||||
|
||||
assertThat(orderedIds).contains(onlineClerkId, offlineClerkId);
|
||||
assertThat(orderedIds.indexOf(onlineClerkId))
|
||||
.withFailMessage("Unexpected order for token %s: %s | response: %s",
|
||||
filterToken, orderedIds, responseBody)
|
||||
.isLessThan(orderedIds.indexOf(offlineClerkId));
|
||||
}
|
||||
|
||||
@Test
|
||||
// 场景:两个等级都未配置排序号时,接口仍可返回且在线客服优先排序。
|
||||
void listOrdersByOnlineStateWhenOrderNumberMissing() throws Exception {
|
||||
ensureTenantContext();
|
||||
PlayClerkLevelInfoEntity onlineLevel = createClerkLevel("null-online", null, 20);
|
||||
PlayClerkLevelInfoEntity offlineLevel = createClerkLevel("null-offline", null, 30);
|
||||
|
||||
String filterToken = "null-priority-" + IdUtils.getUuid().substring(0, 8);
|
||||
String onlineClerkId = createClerk(filterToken + "-online", onlineLevel.getId(), "1");
|
||||
String offlineClerkId = createClerk(filterToken + "-offline", offlineLevel.getId(), "0");
|
||||
|
||||
MvcResult result = mockMvc.perform(get("/clerk/user/list")
|
||||
.param("pageNum", "1")
|
||||
.param("pageSize", "20")
|
||||
.param("nickname", filterToken)
|
||||
.header(TENANT_HEADER, DEFAULT_TENANT)
|
||||
.header(USER_HEADER, DEFAULT_USER))
|
||||
.andExpect(status().isOk())
|
||||
.andReturn();
|
||||
|
||||
String responseBody = result.getResponse().getContentAsString();
|
||||
JsonNode root = objectMapper.readTree(responseBody);
|
||||
assertThat(root.get("code").asInt()).isEqualTo(200);
|
||||
JsonNode records = root.path("data");
|
||||
assertThat(records.isArray()).as("Response payload: %s", responseBody).isTrue();
|
||||
|
||||
List<String> orderedIds = new ArrayList<>();
|
||||
for (JsonNode record : records) {
|
||||
orderedIds.add(record.path("id").asText());
|
||||
}
|
||||
|
||||
assertThat(orderedIds).contains(onlineClerkId, offlineClerkId);
|
||||
assertThat(orderedIds.indexOf(onlineClerkId))
|
||||
.withFailMessage("Online clerk should remain prioritized even without orderNumber. token=%s order=%s response=%s",
|
||||
filterToken, orderedIds, responseBody)
|
||||
.isLessThan(orderedIds.indexOf(offlineClerkId));
|
||||
}
|
||||
|
||||
@Test
|
||||
// 场景:存在未填写排序号的等级时,接口仍能返回,并默认将该等级排在有序的等级之后。
|
||||
void listHandlesNullOrderNumberGracefully() throws Exception {
|
||||
ensureTenantContext();
|
||||
PlayClerkLevelInfoEntity orderedLevel = createClerkLevel("ordered", 2L, 40);
|
||||
PlayClerkLevelInfoEntity nullLevel = createClerkLevel("null", null, 50);
|
||||
|
||||
String filterToken = "null-order-" + IdUtils.getUuid().substring(0, 8);
|
||||
String orderedClerkId = createClerk(filterToken + "-ordered", orderedLevel.getId(), "1");
|
||||
String nullOrderClerkId = createClerk(filterToken + "-null", nullLevel.getId(), "1");
|
||||
|
||||
MvcResult result = mockMvc.perform(get("/clerk/user/list")
|
||||
.param("pageNum", "1")
|
||||
.param("pageSize", "20")
|
||||
.param("nickname", filterToken)
|
||||
.header(TENANT_HEADER, DEFAULT_TENANT)
|
||||
.header(USER_HEADER, DEFAULT_USER))
|
||||
.andExpect(status().isOk())
|
||||
.andReturn();
|
||||
|
||||
String responseBody = result.getResponse().getContentAsString();
|
||||
JsonNode root = objectMapper.readTree(responseBody);
|
||||
assertThat(root.get("code").asInt()).isEqualTo(200);
|
||||
JsonNode records = root.path("data");
|
||||
assertThat(records.isArray()).as("Response payload: %s", responseBody).isTrue();
|
||||
|
||||
List<String> orderedIds = new ArrayList<>();
|
||||
for (JsonNode record : records) {
|
||||
orderedIds.add(record.path("id").asText());
|
||||
}
|
||||
|
||||
assertThat(orderedIds).contains(orderedClerkId, nullOrderClerkId);
|
||||
assertThat(orderedIds.indexOf(orderedClerkId))
|
||||
.withFailMessage("Null orderNumber should fall back after populated ones. token=%s, order=%s, response=%s",
|
||||
filterToken, orderedIds, responseBody)
|
||||
.isLessThan(orderedIds.indexOf(nullOrderClerkId));
|
||||
}
|
||||
|
||||
@Test
|
||||
// 场景:更新店员等级时传入排序号,接口应成功持久化该值,验证新增字段的写入能力。
|
||||
void updateLevelPersistsOrderNumber() throws Exception {
|
||||
ensureTenantContext();
|
||||
PlayClerkLevelInfoEntity level = createClerkLevel("update", 8L, 80);
|
||||
|
||||
long updatedOrderNumber = 42L;
|
||||
ObjectNode payload = objectMapper.createObjectNode();
|
||||
payload.put("id", level.getId());
|
||||
payload.put("name", level.getName());
|
||||
payload.put("firstRegularRatio", level.getFirstRegularRatio());
|
||||
payload.put("notFirstRegularRatio", level.getNotFirstRegularRatio());
|
||||
payload.put("firstRewardRatio", level.getFirstRewardRatio());
|
||||
payload.put("notFirstRewardRatio", level.getNotFirstRewardRatio());
|
||||
payload.put("firstRandomRadio", level.getFirstRandomRadio());
|
||||
payload.put("notFirstRandomRadio", level.getNotFirstRandomRadio());
|
||||
payload.put("styleType", level.getStyleType());
|
||||
payload.put("orderNumber", updatedOrderNumber);
|
||||
|
||||
mockMvc.perform(post("/clerk/level/update")
|
||||
.header(TENANT_HEADER, DEFAULT_TENANT)
|
||||
.header(USER_HEADER, DEFAULT_USER)
|
||||
.contentType(MediaType.APPLICATION_JSON)
|
||||
.content(payload.toString()))
|
||||
.andExpect(status().isOk())
|
||||
.andExpect(jsonPath("$.code").value(200));
|
||||
|
||||
ensureTenantContext();
|
||||
PlayClerkLevelInfoEntity reloaded = clerkLevelInfoService.getById(level.getId());
|
||||
assertThat(reloaded.getOrderNumber()).isEqualTo(updatedOrderNumber);
|
||||
}
|
||||
|
||||
@Test
|
||||
// 场景:更新时清空排序号,接口应允许写入null并持久化。
|
||||
void updateLevelAllowsClearingOrderNumber() throws Exception {
|
||||
ensureTenantContext();
|
||||
PlayClerkLevelInfoEntity level = createClerkLevel("clear", 5L, 85);
|
||||
|
||||
ObjectNode payload = objectMapper.createObjectNode();
|
||||
payload.put("id", level.getId());
|
||||
payload.put("name", level.getName());
|
||||
payload.put("firstRegularRatio", level.getFirstRegularRatio());
|
||||
payload.put("notFirstRegularRatio", level.getNotFirstRegularRatio());
|
||||
payload.put("firstRewardRatio", level.getFirstRewardRatio());
|
||||
payload.put("notFirstRewardRatio", level.getNotFirstRewardRatio());
|
||||
payload.put("firstRandomRadio", level.getFirstRandomRadio());
|
||||
payload.put("notFirstRandomRadio", level.getNotFirstRandomRadio());
|
||||
payload.put("styleType", level.getStyleType());
|
||||
payload.putNull("orderNumber");
|
||||
|
||||
mockMvc.perform(post("/clerk/level/update")
|
||||
.header(TENANT_HEADER, DEFAULT_TENANT)
|
||||
.header(USER_HEADER, DEFAULT_USER)
|
||||
.contentType(MediaType.APPLICATION_JSON)
|
||||
.content(payload.toString()))
|
||||
.andExpect(status().isOk())
|
||||
.andExpect(jsonPath("$.code").value(200));
|
||||
|
||||
ensureTenantContext();
|
||||
PlayClerkLevelInfoEntity reloaded = clerkLevelInfoService.getById(level.getId());
|
||||
assertThat(reloaded.getOrderNumber()).isNull();
|
||||
}
|
||||
|
||||
private void ensureTenantContext() {
|
||||
SecurityUtils.setTenantId(DEFAULT_TENANT);
|
||||
}
|
||||
|
||||
private PlayClerkLevelInfoEntity createClerkLevel(String suffix, Long orderNumber, int levelValue) {
|
||||
ensureTenantContext();
|
||||
String levelId = IdUtils.getUuid();
|
||||
PlayClerkLevelInfoEntity level = new PlayClerkLevelInfoEntity();
|
||||
level.setId(levelId);
|
||||
level.setTenantId(DEFAULT_TENANT);
|
||||
level.setName("API测试等级-" + suffix);
|
||||
level.setLevel(levelValue);
|
||||
level.setFirstRegularRatio(60);
|
||||
level.setNotFirstRegularRatio(50);
|
||||
level.setFirstRewardRatio(45);
|
||||
level.setNotFirstRewardRatio(35);
|
||||
level.setFirstRandomRadio(55);
|
||||
level.setNotFirstRandomRadio(40);
|
||||
level.setStyleType(levelValue);
|
||||
level.setOrderNumber(orderNumber);
|
||||
clerkLevelInfoService.save(level);
|
||||
levelIdsToCleanup.add(levelId);
|
||||
return level;
|
||||
}
|
||||
|
||||
private String createClerk(String suffix, String levelId, String onlineState) {
|
||||
ensureTenantContext();
|
||||
String clerkId = IdUtils.getUuid();
|
||||
PlayClerkUserInfoEntity clerk = new PlayClerkUserInfoEntity();
|
||||
clerk.setId(clerkId);
|
||||
clerk.setTenantId(DEFAULT_TENANT);
|
||||
clerk.setNickname("API测试店员-" + suffix);
|
||||
clerk.setLevelId(levelId);
|
||||
clerk.setClerkState("1");
|
||||
clerk.setOnboardingState("1");
|
||||
clerk.setListingState("1");
|
||||
clerk.setDisplayState("1");
|
||||
clerk.setRecommendationState("0");
|
||||
clerk.setPinToTopState("0");
|
||||
clerk.setRandomOrderState("1");
|
||||
clerk.setFixingLevel("0");
|
||||
clerk.setOnlineState(onlineState);
|
||||
clerk.setPhone("138" + String.format("%08d", ThreadLocalRandom.current().nextInt(0, 100_000_000)));
|
||||
clerk.setOpenid("openid-" + suffix + "-" + IdUtils.getUuid());
|
||||
clerk.setWeiChatCode("wx-code-" + suffix);
|
||||
clerk.setWeiChatAvatar("https://example.com/avatar/" + suffix);
|
||||
clerk.setTypeId("api-type");
|
||||
clerk.setProvince("API省");
|
||||
clerk.setCity("API市");
|
||||
clerk.setEntryTime(LocalDateTime.now());
|
||||
clerk.setAddTime(LocalDateTime.now());
|
||||
clerkUserInfoService.save(clerk);
|
||||
clerkIdsToCleanup.add(clerkId);
|
||||
return clerkId;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user