暂存提交
This commit is contained in:
@@ -0,0 +1,27 @@
|
||||
package com.baiyue.firstleg.dto;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import jakarta.validation.constraints.Max;
|
||||
import jakarta.validation.constraints.Min;
|
||||
import jakarta.validation.constraints.Size;
|
||||
import jakarta.validation.constraints.Pattern;
|
||||
|
||||
/** 头程履约任务分页查询条件。 */
|
||||
@Schema(name = "FulfillmentTaskQuery", description = "头程履约任务分页查询条件")
|
||||
public record FulfillmentTaskQuery(
|
||||
@Schema(description = "订单号关键字") @Size(max = 64) String keyword,
|
||||
@Schema(description = "任务状态")
|
||||
@Size(max = 24) @Pattern(regexp = "PENDING_ASSIGNMENT|ASSIGNED|PROCESSING|COMPLETED|CANCELLED") String status,
|
||||
@Schema(description = "负责人用户ID") Long assigneeId,
|
||||
@Schema(description = "页码", defaultValue = "1") @Min(1) long page,
|
||||
@Schema(description = "每页条数", defaultValue = "20") @Min(1) @Max(200) long size
|
||||
) {
|
||||
public FulfillmentTaskQuery {
|
||||
if (page == 0) {
|
||||
page = 1;
|
||||
}
|
||||
if (size == 0) {
|
||||
size = 20;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
SET NAMES utf8mb4;
|
||||
USE baiyue_firstleg;
|
||||
|
||||
-- 既有履约任务表补充分页查询索引;重复执行时不重复创建。
|
||||
SET @firstleg_task_list_index_sql = IF(
|
||||
EXISTS(SELECT 1 FROM information_schema.statistics
|
||||
WHERE table_schema = DATABASE() AND table_name = 'fl_fulfillment_task'
|
||||
AND index_name = 'idx_task_tenant_created'),
|
||||
'SELECT 1',
|
||||
'CREATE INDEX idx_task_tenant_created ON fl_fulfillment_task (tenant_id, created_at)'
|
||||
);
|
||||
PREPARE firstleg_task_list_index_stmt FROM @firstleg_task_list_index_sql;
|
||||
EXECUTE firstleg_task_list_index_stmt;
|
||||
DEALLOCATE PREPARE firstleg_task_list_index_stmt;
|
||||
@@ -0,0 +1,106 @@
|
||||
openapi: 3.0.3
|
||||
info:
|
||||
title: 柏悦头程履约 API
|
||||
version: 1.1.0
|
||||
security:
|
||||
- bearerAuth: []
|
||||
paths:
|
||||
/api/platform/v1/first-leg/tasks:
|
||||
get:
|
||||
summary: 分页查询履约任务
|
||||
description: 需要 platform:firstleg:task:list 权限
|
||||
parameters:
|
||||
- $ref: '#/components/parameters/TenantId'
|
||||
- $ref: '#/components/parameters/Page'
|
||||
- $ref: '#/components/parameters/Size'
|
||||
- {name: keyword, in: query, schema: {type: string, maxLength: 64}}
|
||||
- {name: status, in: query, schema: {type: string, enum: [PENDING_ASSIGNMENT, ASSIGNED, PROCESSING, COMPLETED, CANCELLED]}}
|
||||
- {name: assigneeId, in: query, schema: {type: integer, format: int64}}
|
||||
responses:
|
||||
'200': {description: 查询成功}
|
||||
'403': {description: 无查询权限}
|
||||
/api/platform/v1/first-leg/tasks/{taskId}:
|
||||
get:
|
||||
summary: 查询履约任务详情
|
||||
description: 需要 platform:firstleg:task:view 权限
|
||||
parameters:
|
||||
- $ref: '#/components/parameters/TenantId'
|
||||
- $ref: '#/components/parameters/TaskId'
|
||||
responses:
|
||||
'200': {description: 查询成功}
|
||||
'403': {description: 无查看权限}
|
||||
'404': {description: 任务不存在}
|
||||
/api/platform/v1/first-leg/tasks/by-order/{orderId}:
|
||||
get:
|
||||
summary: 按订单查询履约任务
|
||||
description: 需要 platform:firstleg:task:view 权限
|
||||
parameters:
|
||||
- $ref: '#/components/parameters/TenantId'
|
||||
- {name: orderId, in: path, required: true, schema: {type: integer, format: int64}}
|
||||
responses:
|
||||
'200': {description: 查询成功}
|
||||
'403': {description: 无查看权限}
|
||||
'404': {description: 任务不存在}
|
||||
/api/platform/v1/first-leg/tasks/{taskId}/assignment-history:
|
||||
get:
|
||||
summary: 分页查询任务分配历史
|
||||
description: 需要 platform:firstleg:assignment:history 权限
|
||||
parameters:
|
||||
- $ref: '#/components/parameters/TenantId'
|
||||
- $ref: '#/components/parameters/TaskId'
|
||||
- $ref: '#/components/parameters/Page'
|
||||
- $ref: '#/components/parameters/Size'
|
||||
responses:
|
||||
'200': {description: 查询成功}
|
||||
'403': {description: 无历史查看权限}
|
||||
'404': {description: 任务不存在}
|
||||
/api/platform/v1/first-leg/tasks/{taskId}/assignment:
|
||||
post:
|
||||
summary: 分配或改派履约任务
|
||||
description: 需要 platform:firstleg:assignment:assign 权限
|
||||
parameters:
|
||||
- $ref: '#/components/parameters/TenantId'
|
||||
- $ref: '#/components/parameters/TaskId'
|
||||
requestBody:
|
||||
required: true
|
||||
content:
|
||||
application/json:
|
||||
schema: {$ref: '#/components/schemas/AssignRequest'}
|
||||
responses:
|
||||
'200': {description: 分配成功}
|
||||
'403': {description: 无分配权限}
|
||||
'404': {description: 任务不存在}
|
||||
'409': {description: 任务已关闭或发生并发更新}
|
||||
components:
|
||||
securitySchemes:
|
||||
bearerAuth:
|
||||
type: http
|
||||
scheme: bearer
|
||||
bearerFormat: JWT
|
||||
parameters:
|
||||
TenantId:
|
||||
name: tenantId
|
||||
in: query
|
||||
required: true
|
||||
schema: {type: integer, format: int64, minimum: 1}
|
||||
TaskId:
|
||||
name: taskId
|
||||
in: path
|
||||
required: true
|
||||
schema: {type: integer, format: int64}
|
||||
Page:
|
||||
name: page
|
||||
in: query
|
||||
schema: {type: integer, format: int64, minimum: 1, default: 1}
|
||||
Size:
|
||||
name: size
|
||||
in: query
|
||||
schema: {type: integer, format: int64, minimum: 1, maximum: 200, default: 20}
|
||||
schemas:
|
||||
AssignRequest:
|
||||
type: object
|
||||
required: [assigneeId, assigneeName]
|
||||
properties:
|
||||
assigneeId: {type: integer, format: int64}
|
||||
assigneeName: {type: string, maxLength: 64}
|
||||
reason: {type: string, maxLength: 500}
|
||||
+55
@@ -0,0 +1,55 @@
|
||||
package com.baiyue.firstleg.controller;
|
||||
|
||||
import com.baiyue.common.security.AuthenticatedUser;
|
||||
import com.baiyue.firstleg.dto.AssignRequest;
|
||||
import com.baiyue.firstleg.dto.FulfillmentTaskQuery;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.springframework.security.access.prepost.PreAuthorize;
|
||||
import org.springframework.core.io.ClassPathResource;
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
class FulfillmentTaskControllerContractTest {
|
||||
@Test
|
||||
void 查询和分配接口声明对应权限码() throws Exception {
|
||||
assertAuthority("page", "hasAuthority('platform:firstleg:task:list')",
|
||||
AuthenticatedUser.class, long.class, FulfillmentTaskQuery.class);
|
||||
assertAuthority("detail", "hasAuthority('platform:firstleg:task:view')",
|
||||
AuthenticatedUser.class, long.class, long.class);
|
||||
assertAuthority("byOrder", "hasAuthority('platform:firstleg:task:view')",
|
||||
AuthenticatedUser.class, long.class, long.class);
|
||||
assertAuthority("assignmentHistory", "hasAuthority('platform:firstleg:assignment:history')",
|
||||
AuthenticatedUser.class, long.class, long.class, long.class, long.class);
|
||||
assertAuthority("assign", "hasAuthority('platform:firstleg:assignment:assign')",
|
||||
AuthenticatedUser.class, long.class, long.class, AssignRequest.class);
|
||||
}
|
||||
|
||||
@Test
|
||||
void 分页查询缺省值为第一页每页二十条() {
|
||||
FulfillmentTaskQuery query = new FulfillmentTaskQuery(null, null, null, 0, 0);
|
||||
assertThat(query.page()).isEqualTo(1);
|
||||
assertThat(query.size()).isEqualTo(20);
|
||||
}
|
||||
|
||||
@Test
|
||||
void OpenAPI覆盖四类只读接口和对应权限() throws Exception {
|
||||
String openapi = new ClassPathResource("openapi/firstleg-v1.yaml")
|
||||
.getContentAsString(StandardCharsets.UTF_8);
|
||||
assertThat(openapi)
|
||||
.contains("/api/platform/v1/first-leg/tasks:")
|
||||
.contains("/api/platform/v1/first-leg/tasks/{taskId}:")
|
||||
.contains("/api/platform/v1/first-leg/tasks/by-order/{orderId}:")
|
||||
.contains("/api/platform/v1/first-leg/tasks/{taskId}/assignment-history:")
|
||||
.contains("platform:firstleg:task:list")
|
||||
.contains("platform:firstleg:assignment:history");
|
||||
}
|
||||
|
||||
private void assertAuthority(String methodName, String permission, Class<?>... parameterTypes)
|
||||
throws NoSuchMethodException {
|
||||
Method method = PlatformFulfillmentAssignmentController.class.getDeclaredMethod(methodName, parameterTypes);
|
||||
assertThat(method.getAnnotation(PreAuthorize.class).value()).isEqualTo(permission);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,65 @@
|
||||
package com.baiyue.firstleg.service;
|
||||
|
||||
import com.baiyue.common.core.api.PageResult;
|
||||
import com.baiyue.common.core.api.ResultCode;
|
||||
import com.baiyue.common.core.exception.BizException;
|
||||
import com.baiyue.firstleg.dto.FulfillmentTaskQuery;
|
||||
import com.baiyue.firstleg.entity.FulfillmentTaskEntity;
|
||||
import com.baiyue.firstleg.repository.FulfillmentTaskRepository;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.springframework.test.util.ReflectionTestUtils;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.assertj.core.api.Assertions.assertThatThrownBy;
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.verify;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
class FulfillmentTaskServiceTest {
|
||||
@Test
|
||||
void 列表查询保留租户和分页条件() {
|
||||
FulfillmentTaskRepository repository = mock(FulfillmentTaskRepository.class);
|
||||
FulfillmentTaskQuery query = new FulfillmentTaskQuery(null, null, null, 1, 20);
|
||||
PageResult<FulfillmentTaskEntity> expected = new PageResult<>(List.of(), 1, 20, 0, 0);
|
||||
when(repository.page(10001L, query)).thenReturn(expected);
|
||||
|
||||
assertThat(service(repository).page(10001L, query)).isSameAs(expected);
|
||||
verify(repository).page(10001L, query);
|
||||
}
|
||||
|
||||
@Test
|
||||
void 详情和按订单查询不存在时返回404() {
|
||||
FulfillmentTaskRepository repository = mock(FulfillmentTaskRepository.class);
|
||||
FulfillmentTaskService service = service(repository);
|
||||
|
||||
assertThatThrownBy(() -> service.detail(10001L, 1L))
|
||||
.isInstanceOf(BizException.class)
|
||||
.extracting(exception -> ((BizException) exception).getResultCode())
|
||||
.isEqualTo(ResultCode.NOT_FOUND);
|
||||
assertThatThrownBy(() -> service.byOrder(10001L, 2L))
|
||||
.isInstanceOf(BizException.class)
|
||||
.extracting(exception -> ((BizException) exception).getResultCode())
|
||||
.isEqualTo(ResultCode.NOT_FOUND);
|
||||
}
|
||||
|
||||
@Test
|
||||
void 查询分配历史前先校验任务归属租户() {
|
||||
FulfillmentTaskRepository repository = mock(FulfillmentTaskRepository.class);
|
||||
FulfillmentTaskEntity task = new FulfillmentTaskEntity();
|
||||
when(repository.findOwned(10001L, 1L)).thenReturn(task);
|
||||
PageResult<com.baiyue.firstleg.entity.AssignmentHistoryEntity> expected =
|
||||
new PageResult<>(List.of(), 1, 20, 0, 0);
|
||||
when(repository.pageHistory(10001L, 1L, 1, 20)).thenReturn(expected);
|
||||
|
||||
assertThat(service(repository).assignmentHistory(10001L, 1L, 1, 20)).isSameAs(expected);
|
||||
verify(repository).findOwned(10001L, 1L);
|
||||
}
|
||||
|
||||
private FulfillmentTaskService service(FulfillmentTaskRepository repository) {
|
||||
FulfillmentTaskService service = new FulfillmentTaskService();
|
||||
ReflectionTestUtils.setField(service, "repository", repository);
|
||||
return service;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user