优化
This commit is contained in:
+5
-3
@@ -13,6 +13,7 @@ import com.baiyue.warehouse.entity.ExpressCompanyEntity;
|
||||
import com.baiyue.warehouse.service.ExpressCompanyQueryService;
|
||||
import com.baiyue.warehouse.service.ExpressCompanyImportService;
|
||||
import io.swagger.v3.oas.annotations.Operation;
|
||||
import io.swagger.v3.oas.annotations.Parameter;
|
||||
import io.swagger.v3.oas.annotations.responses.ApiResponses;
|
||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||
import jakarta.validation.Valid;
|
||||
@@ -42,7 +43,7 @@ import java.nio.charset.StandardCharsets;
|
||||
|
||||
/** 平台快递公司管理接口。 */
|
||||
@Validated
|
||||
@Tag(name = "平台快递公司", description = "按目标租户分页查询快递公司主数据")
|
||||
@Tag(name = "平台快递公司", description = "跨企业分页查询和按目标租户维护快递公司主数据")
|
||||
@RestController
|
||||
@RequestMapping("/api/platform/v1/express-companies")
|
||||
public class PlatformExpressCompanyController {
|
||||
@@ -56,7 +57,7 @@ public class PlatformExpressCompanyController {
|
||||
|
||||
@GetMapping
|
||||
@PreAuthorize("hasAuthority('platform:express:list')")
|
||||
@Operation(summary = "分页查询快递公司", description = "按目标租户、关键字和状态分页查询快递公司")
|
||||
@Operation(summary = "分页查询快递公司", description = "默认查询全部企业;可按目标租户、关键字和状态筛选")
|
||||
@ApiResponses({
|
||||
@io.swagger.v3.oas.annotations.responses.ApiResponse(responseCode = "200", description = "查询成功"),
|
||||
@io.swagger.v3.oas.annotations.responses.ApiResponse(responseCode = "400", description = "查询条件无效"),
|
||||
@@ -65,7 +66,8 @@ public class PlatformExpressCompanyController {
|
||||
})
|
||||
public ApiResponse<PageResult<ExpressCompanyEntity>> page(
|
||||
@AuthenticationPrincipal AuthenticatedUser user,
|
||||
@RequestParam @Min(1) long tenantId,
|
||||
@Parameter(description = "可选目标企业租户ID;不传时查询全部企业")
|
||||
@RequestParam(required = false) @Min(1) Long tenantId,
|
||||
@Valid @ParameterObject ExpressCompanyPageQuery query) {
|
||||
requirePlatform(user);
|
||||
return ApiResponse.success(service.page(tenantId, query));
|
||||
|
||||
+6
-3
@@ -13,6 +13,7 @@ import com.baiyue.warehouse.entity.PartnerEntity;
|
||||
import com.baiyue.warehouse.service.PlatformPartnerQueryService;
|
||||
import com.baiyue.warehouse.service.PartnerImportService;
|
||||
import io.swagger.v3.oas.annotations.Operation;
|
||||
import io.swagger.v3.oas.annotations.Parameter;
|
||||
import io.swagger.v3.oas.annotations.responses.ApiResponses;
|
||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||
import jakarta.validation.Valid;
|
||||
@@ -42,7 +43,7 @@ import java.nio.charset.StandardCharsets;
|
||||
|
||||
/** 平台往来单位管理接口。 */
|
||||
@Validated
|
||||
@Tag(name = "平台往来单位", description = "按目标租户分页查询往来单位主数据")
|
||||
@Tag(name = "平台往来单位", description = "跨企业分页查询和按目标租户维护往来单位主数据")
|
||||
@RestController
|
||||
@RequestMapping("/api/platform/v1/partners")
|
||||
public class PlatformPartnerController {
|
||||
@@ -83,7 +84,8 @@ public class PlatformPartnerController {
|
||||
|
||||
@GetMapping
|
||||
@PreAuthorize("hasAuthority('platform:counterparty:list')")
|
||||
@Operation(summary = "分页查询往来单位", description = "按目标租户、关键字、类型和状态分页查询往来单位")
|
||||
@Operation(summary = "分页查询往来单位",
|
||||
description = "默认分页查询全部企业往来单位;可按目标租户、关键字、类型和状态筛选")
|
||||
@ApiResponses({
|
||||
@io.swagger.v3.oas.annotations.responses.ApiResponse(responseCode = "200", description = "查询成功"),
|
||||
@io.swagger.v3.oas.annotations.responses.ApiResponse(responseCode = "400", description = "查询条件无效"),
|
||||
@@ -92,7 +94,8 @@ public class PlatformPartnerController {
|
||||
})
|
||||
public ApiResponse<PageResult<PartnerEntity>> page(
|
||||
@AuthenticationPrincipal AuthenticatedUser user,
|
||||
@RequestParam @Min(1) long tenantId,
|
||||
@Parameter(description = "可选目标企业租户ID;不传时查询全部企业")
|
||||
@RequestParam(required = false) @Min(1) Long tenantId,
|
||||
@Valid @ParameterObject PartnerPageQuery query) {
|
||||
requirePlatform(user);
|
||||
return ApiResponse.success(service.page(tenantId, query));
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
package com.baiyue.warehouse.mapper;
|
||||
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
||||
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||
import com.baiyue.warehouse.entity.PartnerEntity;
|
||||
import com.baiyue.warehouse.entity.PartnerTypeEntity;
|
||||
import org.apache.ibatis.annotations.Delete;
|
||||
@@ -25,6 +26,56 @@ public interface PartnerMapper extends BaseMapper<PartnerEntity> {
|
||||
@Select("SELECT partner_id FROM wh_partner_type WHERE tenant_id = #{tenantId} AND partner_type = #{type}")
|
||||
List<Long> selectPartnerIdsByType(@Param("tenantId") long tenantId, @Param("type") String type);
|
||||
|
||||
@Select("""
|
||||
<script>
|
||||
SELECT p.*
|
||||
FROM wh_partner p
|
||||
WHERE p.deleted = 0
|
||||
<if test="tenantId != null">
|
||||
AND p.tenant_id = #{tenantId}
|
||||
</if>
|
||||
<choose>
|
||||
<when test="type == 'BOTH'">
|
||||
AND EXISTS (
|
||||
SELECT 1 FROM wh_partner_type customer_type
|
||||
WHERE customer_type.partner_id = p.id
|
||||
AND customer_type.partner_type = 'CUSTOMER'
|
||||
AND customer_type.tenant_id = p.tenant_id
|
||||
)
|
||||
AND EXISTS (
|
||||
SELECT 1 FROM wh_partner_type supplier_type
|
||||
WHERE supplier_type.partner_id = p.id
|
||||
AND supplier_type.partner_type = 'SUPPLIER'
|
||||
AND supplier_type.tenant_id = p.tenant_id
|
||||
)
|
||||
</when>
|
||||
<otherwise>
|
||||
AND EXISTS (
|
||||
SELECT 1 FROM wh_partner_type pt
|
||||
WHERE pt.partner_id = p.id
|
||||
AND pt.partner_type = #{type}
|
||||
AND pt.tenant_id = p.tenant_id
|
||||
)
|
||||
</otherwise>
|
||||
</choose>
|
||||
<if test="status != null and status != ''">
|
||||
AND p.status = #{status}
|
||||
</if>
|
||||
<if test="keyword != null and keyword != ''">
|
||||
AND (p.partner_code LIKE CONCAT('%', #{keyword}, '%')
|
||||
OR p.partner_name LIKE CONCAT('%', #{keyword}, '%')
|
||||
OR p.contact_name LIKE CONCAT('%', #{keyword}, '%')
|
||||
OR p.contact_phone LIKE CONCAT('%', #{keyword}, '%'))
|
||||
</if>
|
||||
ORDER BY p.partner_name ASC, p.id ASC
|
||||
</script>
|
||||
""")
|
||||
Page<PartnerEntity> selectPartnerPageByType(Page<PartnerEntity> page,
|
||||
@Param("tenantId") Long tenantId,
|
||||
@Param("type") String type,
|
||||
@Param("status") String status,
|
||||
@Param("keyword") String keyword);
|
||||
|
||||
@Delete("DELETE FROM wh_partner_type WHERE partner_id = #{partnerId}")
|
||||
void deleteTypes(@Param("partnerId") long partnerId);
|
||||
|
||||
|
||||
+3
-3
@@ -9,7 +9,7 @@ import com.baiyue.warehouse.mapper.ExpressCompanyMapper;
|
||||
import org.springframework.stereotype.Repository;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
/** 快递公司主数据仓储。 */
|
||||
/** 快递公司主数据仓储;平台分页租户条件可选,资源读写仍强制租户边界。 */
|
||||
@Repository
|
||||
public class ExpressCompanyRepository {
|
||||
private final ExpressCompanyMapper mapper;
|
||||
@@ -18,9 +18,9 @@ public class ExpressCompanyRepository {
|
||||
this.mapper = mapper;
|
||||
}
|
||||
|
||||
public PageResult<ExpressCompanyEntity> page(long tenantId, ExpressCompanyPageQuery query) {
|
||||
public PageResult<ExpressCompanyEntity> page(Long tenantId, ExpressCompanyPageQuery query) {
|
||||
LambdaQueryWrapper<ExpressCompanyEntity> wrapper = new LambdaQueryWrapper<ExpressCompanyEntity>()
|
||||
.eq(ExpressCompanyEntity::getTenantId, tenantId)
|
||||
.eq(tenantId != null, ExpressCompanyEntity::getTenantId, tenantId)
|
||||
.eq(StringUtils.hasText(query.status()), ExpressCompanyEntity::getStatus, query.status())
|
||||
.and(StringUtils.hasText(query.keyword()), condition -> condition
|
||||
.like(ExpressCompanyEntity::getCompanyCode, query.keyword())
|
||||
|
||||
@@ -41,14 +41,17 @@ public class PartnerRepository {
|
||||
return entity;
|
||||
}
|
||||
|
||||
public PageResult<PartnerEntity> page(long tenantId, PartnerPageQuery request) {
|
||||
List<Long> typedIds = typedIds(tenantId, request.type());
|
||||
if (StringUtils.hasText(request.type()) && typedIds.isEmpty()) {
|
||||
return new PageResult<>(List.of(), request.page(), request.size(), 0, 0);
|
||||
public PageResult<PartnerEntity> page(Long tenantId, PartnerPageQuery request) {
|
||||
if (StringUtils.hasText(request.type())) {
|
||||
Page<PartnerEntity> page = mapper.selectPartnerPageByType(
|
||||
new Page<>(request.page(), request.size()), tenantId, request.type(),
|
||||
request.status(), request.keyword());
|
||||
PageResult<PartnerEntity> result = PageResult.from(page);
|
||||
hydrateTypes(result.records());
|
||||
return result;
|
||||
}
|
||||
LambdaQueryWrapper<PartnerEntity> wrapper = new LambdaQueryWrapper<PartnerEntity>()
|
||||
.eq(PartnerEntity::getTenantId, tenantId)
|
||||
.in(StringUtils.hasText(request.type()), PartnerEntity::getId, typedIds)
|
||||
.eq(tenantId != null, PartnerEntity::getTenantId, tenantId)
|
||||
.eq(StringUtils.hasText(request.status()), PartnerEntity::getStatus, request.status())
|
||||
.and(StringUtils.hasText(request.keyword()), query -> query
|
||||
.like(PartnerEntity::getPartnerCode, request.keyword())
|
||||
|
||||
+1
-1
@@ -21,7 +21,7 @@ public class ExpressCompanyQueryService {
|
||||
this.repository = repository;
|
||||
}
|
||||
|
||||
public PageResult<ExpressCompanyEntity> page(long tenantId, ExpressCompanyPageQuery query) {
|
||||
public PageResult<ExpressCompanyEntity> page(Long tenantId, ExpressCompanyPageQuery query) {
|
||||
return repository.page(tenantId, query);
|
||||
}
|
||||
|
||||
|
||||
+1
-1
@@ -25,7 +25,7 @@ public class PlatformPartnerQueryService {
|
||||
this.repository = repository;
|
||||
}
|
||||
|
||||
public PageResult<PartnerEntity> page(long tenantId, PartnerPageQuery query) {
|
||||
public PageResult<PartnerEntity> page(Long tenantId, PartnerPageQuery query) {
|
||||
return repository.page(tenantId, query);
|
||||
}
|
||||
|
||||
|
||||
+31
@@ -0,0 +1,31 @@
|
||||
package com.baiyue.warehouse.controller;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.springframework.web.bind.annotation.RequestParam;
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.Arrays;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
class PlatformExpressCompanyAllTenantQueryContractTest {
|
||||
@Test
|
||||
void 分页租户参数可选但详情写入启停和导入仍然必填() {
|
||||
Method page = method("page");
|
||||
assertThat(page.getParameterTypes()[1]).isEqualTo(Long.class);
|
||||
assertThat(page.getParameters()[1].getAnnotation(RequestParam.class).required()).isFalse();
|
||||
|
||||
for (String scopedMethod : new String[] {"detail", "create", "update", "changeStatus", "importCompanies"}) {
|
||||
Method method = method(scopedMethod);
|
||||
assertThat(method.getParameterTypes()[1]).isEqualTo(long.class);
|
||||
assertThat(method.getParameters()[1].getAnnotation(RequestParam.class).required()).isTrue();
|
||||
}
|
||||
}
|
||||
|
||||
private static Method method(String name) {
|
||||
return Arrays.stream(PlatformExpressCompanyController.class.getDeclaredMethods())
|
||||
.filter(candidate -> candidate.getName().equals(name))
|
||||
.findFirst()
|
||||
.orElseThrow();
|
||||
}
|
||||
}
|
||||
+1
-1
@@ -75,7 +75,7 @@ class PlatformMasterDataControllerContractTest {
|
||||
|
||||
Method page = controller.getDeclaredMethod("page",
|
||||
com.baiyue.common.security.AuthenticatedUser.class,
|
||||
long.class,
|
||||
Long.class,
|
||||
controller == PlatformPartnerController.class
|
||||
? com.baiyue.warehouse.dto.MasterDataQueries.PartnerPageQuery.class
|
||||
: com.baiyue.warehouse.dto.MasterDataQueries.ExpressCompanyPageQuery.class);
|
||||
|
||||
+64
@@ -0,0 +1,64 @@
|
||||
package com.baiyue.warehouse.controller;
|
||||
|
||||
import com.baiyue.warehouse.dto.MasterDataQueries.PartnerPageQuery;
|
||||
import com.baiyue.warehouse.mapper.PartnerMapper;
|
||||
import com.baiyue.warehouse.repository.PartnerRepository;
|
||||
import com.baiyue.warehouse.service.PlatformPartnerQueryService;
|
||||
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||
import org.apache.ibatis.annotations.Select;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.springframework.web.bind.annotation.RequestParam;
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
class PlatformPartnerAllTenantQueryContractTest {
|
||||
@Test
|
||||
void 平台分页租户可选但详情写入和导入仍要求租户() {
|
||||
Method page = method(PlatformPartnerController.class, "page");
|
||||
assertThat(page.getParameterTypes()[1]).isEqualTo(Long.class);
|
||||
assertThat(page.getParameters()[1].getAnnotation(RequestParam.class).required()).isFalse();
|
||||
|
||||
for (String scopedMethod : new String[] {"importPartners", "detail", "create", "update", "changeStatus"}) {
|
||||
Method method = method(PlatformPartnerController.class, scopedMethod);
|
||||
assertThat(method.getParameterTypes()[1]).isEqualTo(long.class);
|
||||
assertThat(method.getParameters()[1].getAnnotation(RequestParam.class).required()).isTrue();
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
void 分页链路使用可选租户而其他仓储方法保持原有强租户边界() throws Exception {
|
||||
assertThat(PlatformPartnerQueryService.class.getMethod("page", Long.class, PartnerPageQuery.class))
|
||||
.isNotNull();
|
||||
assertThat(PartnerRepository.class.getMethod("page", Long.class, PartnerPageQuery.class))
|
||||
.isNotNull();
|
||||
assertThat(PartnerRepository.class.getMethod("findOwned", long.class, long.class))
|
||||
.isNotNull();
|
||||
assertThat(PartnerRepository.class.getMethod("existsCode", long.class, String.class, Long.class))
|
||||
.isNotNull();
|
||||
}
|
||||
|
||||
@Test
|
||||
void 类型筛选在数据库内关联分页且租户条件可选() throws Exception {
|
||||
Method method = PartnerMapper.class.getMethod("selectPartnerPageByType",
|
||||
Page.class, Long.class, String.class, String.class, String.class);
|
||||
String sql = String.join("\n", method.getAnnotation(Select.class).value());
|
||||
|
||||
assertThat(sql)
|
||||
.contains("AND EXISTS (")
|
||||
.contains("pt.partner_id = p.id")
|
||||
.contains("pt.partner_type = #{type}")
|
||||
.contains("pt.tenant_id = p.tenant_id")
|
||||
.contains("<if test=\"tenantId != null\">")
|
||||
.contains("AND p.tenant_id = #{tenantId}")
|
||||
.doesNotContain("partner_id IN");
|
||||
}
|
||||
|
||||
private static Method method(Class<?> type, String name) {
|
||||
return java.util.Arrays.stream(type.getDeclaredMethods())
|
||||
.filter(candidate -> candidate.getName().equals(name))
|
||||
.findFirst()
|
||||
.orElseThrow();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
package com.baiyue.warehouse.mapper;
|
||||
|
||||
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||
import org.apache.ibatis.annotations.Select;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
class PartnerMapperContractTest {
|
||||
@Test
|
||||
void bothTypeRequiresCustomerAndSupplierAssociations() throws Exception {
|
||||
Select select = PartnerMapper.class.getDeclaredMethod("selectPartnerPageByType",
|
||||
Page.class, Long.class, String.class, String.class, String.class)
|
||||
.getAnnotation(Select.class);
|
||||
String sql = String.join("\n", select.value());
|
||||
|
||||
assertThat(sql)
|
||||
.contains("<when test=\"type == 'BOTH'\">")
|
||||
.contains("customer_type.partner_type = 'CUSTOMER'")
|
||||
.contains("supplier_type.partner_type = 'SUPPLIER'")
|
||||
.contains("<otherwise>")
|
||||
.contains("pt.partner_type = #{type}");
|
||||
}
|
||||
}
|
||||
+19
-1
@@ -25,7 +25,7 @@ class ExpressCompanyRepositoryTest {
|
||||
}
|
||||
|
||||
@Test
|
||||
void 平台分页强制租户并支持筛选() {
|
||||
void 平台分页传入租户时按租户并支持筛选() {
|
||||
ExpressCompanyMapper mapper = mock(ExpressCompanyMapper.class);
|
||||
when(mapper.selectPage(any(Page.class), any())).thenAnswer(invocation -> invocation.getArgument(0));
|
||||
|
||||
@@ -40,4 +40,22 @@ class ExpressCompanyRepositoryTest {
|
||||
assertThat(wrapper.getValue().getParamNameValuePairs().values())
|
||||
.contains(10001L, "ACTIVE", "%顺丰%");
|
||||
}
|
||||
|
||||
@Test
|
||||
void 平台分页不传租户时查询全部企业并保留其他筛选() {
|
||||
ExpressCompanyMapper mapper = mock(ExpressCompanyMapper.class);
|
||||
when(mapper.selectPage(any(Page.class), any())).thenAnswer(invocation -> invocation.getArgument(0));
|
||||
|
||||
new ExpressCompanyRepository(mapper).page(null,
|
||||
new ExpressCompanyPageQuery(1, 20, "顺丰", "ACTIVE"));
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
ArgumentCaptor<LambdaQueryWrapper<ExpressCompanyEntity>> wrapper =
|
||||
ArgumentCaptor.forClass(LambdaQueryWrapper.class);
|
||||
verify(mapper).selectPage(any(Page.class), wrapper.capture());
|
||||
wrapper.getValue().getSqlSegment();
|
||||
assertThat(wrapper.getValue().getParamNameValuePairs().values())
|
||||
.contains("ACTIVE", "%顺丰%")
|
||||
.doesNotContain(10001L);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -56,17 +56,27 @@ class PartnerRepositoryTest {
|
||||
|
||||
@Test void 平台分页强制租户并支持筛选() {
|
||||
PartnerMapper mapper=mock(PartnerMapper.class);
|
||||
when(mapper.selectPartnerIdsByType(10001L, "CUSTOMER")).thenReturn(List.of(9L));
|
||||
when(mapper.selectPage(any(Page.class), any())).thenAnswer(invocation -> invocation.getArgument(0));
|
||||
when(mapper.selectPartnerPageByType(any(Page.class), eq(10001L), eq("CUSTOMER"),
|
||||
eq("ACTIVE"), eq("示例"))).thenAnswer(invocation -> invocation.getArgument(0));
|
||||
|
||||
new PartnerRepository(mapper).page(10001L,
|
||||
new PartnerPageQuery(1, 20, "示例", "CUSTOMER", "ACTIVE"));
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
ArgumentCaptor<LambdaQueryWrapper<PartnerEntity>> wrapper=ArgumentCaptor.forClass(LambdaQueryWrapper.class);
|
||||
verify(mapper).selectPage(any(Page.class), wrapper.capture());
|
||||
wrapper.getValue().getSqlSegment();
|
||||
assertThat(wrapper.getValue().getParamNameValuePairs().values())
|
||||
.contains(10001L, 9L, "ACTIVE", "%示例%");
|
||||
verify(mapper).selectPartnerPageByType(any(Page.class), eq(10001L), eq("CUSTOMER"),
|
||||
eq("ACTIVE"), eq("示例"));
|
||||
verify(mapper, never()).selectPartnerIdsByType(anyLong(), anyString());
|
||||
}
|
||||
|
||||
@Test void 平台分页不传租户时查询全部企业并支持承运商类型筛选() {
|
||||
PartnerMapper mapper=mock(PartnerMapper.class);
|
||||
when(mapper.selectPartnerPageByType(any(Page.class), isNull(), eq("CARRIER"),
|
||||
eq("ACTIVE"), isNull())).thenAnswer(invocation -> invocation.getArgument(0));
|
||||
|
||||
new PartnerRepository(mapper).page(null,
|
||||
new PartnerPageQuery(1, 20, null, "CARRIER", "ACTIVE"));
|
||||
|
||||
verify(mapper).selectPartnerPageByType(any(Page.class), isNull(), eq("CARRIER"),
|
||||
eq("ACTIVE"), isNull());
|
||||
verify(mapper, never()).selectPartnerIdsByType(anyLong(), anyString());
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user