fix(firstleg): resolve loading list lifecycle by plan
This commit is contained in:
+12
@@ -12,6 +12,7 @@ import com.baiyue.firstleg.dto.LoadingListDtos.PreloadSummary;
|
|||||||
import com.baiyue.firstleg.dto.LoadingListDtos.ConfirmPreloadRequest;
|
import com.baiyue.firstleg.dto.LoadingListDtos.ConfirmPreloadRequest;
|
||||||
import com.baiyue.firstleg.dto.LoadingListDtos.PreloadConfirmationResponse;
|
import com.baiyue.firstleg.dto.LoadingListDtos.PreloadConfirmationResponse;
|
||||||
import com.baiyue.firstleg.dto.LoadingListDtos.TransportUpdateRequest;
|
import com.baiyue.firstleg.dto.LoadingListDtos.TransportUpdateRequest;
|
||||||
|
import com.baiyue.firstleg.dto.LoadingListDtos.LifecycleResolution;
|
||||||
import com.baiyue.firstleg.service.FirstlegScopeGuard;
|
import com.baiyue.firstleg.service.FirstlegScopeGuard;
|
||||||
import com.baiyue.firstleg.service.LoadingListService;
|
import com.baiyue.firstleg.service.LoadingListService;
|
||||||
import io.swagger.v3.oas.annotations.Operation;
|
import io.swagger.v3.oas.annotations.Operation;
|
||||||
@@ -60,6 +61,17 @@ public class PlatformLoadingListController {
|
|||||||
return ApiResponse.success(service.preloadDetail(planId, warehouseId));
|
return ApiResponse.success(service.preloadDetail(planId, warehouseId));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Operation(summary = "解析装柜计划当前详情阶段",
|
||||||
|
description = "按稳定 planId 返回 PRELOAD 或 LOADING_LIST,供页面在计划完成后受控切换详情接口。")
|
||||||
|
@GetMapping("/loading-plans/{planId}/lifecycle")
|
||||||
|
@PreAuthorize("hasAuthority('platform:firstleg:preload:list')")
|
||||||
|
public ApiResponse<LifecycleResolution> lifecycle(
|
||||||
|
@AuthenticationPrincipal AuthenticatedUser user, @PathVariable @Positive long planId,
|
||||||
|
@RequestParam @Positive long warehouseId) {
|
||||||
|
FirstlegScopeGuard.platform(user);
|
||||||
|
return ApiResponse.success(service.lifecycle(planId, warehouseId));
|
||||||
|
}
|
||||||
|
|
||||||
@Operation(summary = "修改装柜运输字段", description = "已推送且仍为 EDITING 的预装清单可补录或修改集装箱号与航次;LOADING 阶段按稳定柜次身份规则维护,不能清空已创建 PDA 任务的柜号。")
|
@Operation(summary = "修改装柜运输字段", description = "已推送且仍为 EDITING 的预装清单可补录或修改集装箱号与航次;LOADING 阶段按稳定柜次身份规则维护,不能清空已创建 PDA 任务的柜号。")
|
||||||
@PatchMapping("/loading-plans/{planId}/transport")
|
@PatchMapping("/loading-plans/{planId}/transport")
|
||||||
@PreAuthorize("hasAuthority('platform:firstleg:preload:edit')")
|
@PreAuthorize("hasAuthority('platform:firstleg:preload:edit')")
|
||||||
|
|||||||
@@ -115,6 +115,17 @@ public final class LoadingListDtos {
|
|||||||
) {
|
) {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public record LifecycleResolution(
|
||||||
|
Long planId,
|
||||||
|
Long containerBookingId,
|
||||||
|
Long warehouseId,
|
||||||
|
String planNo,
|
||||||
|
String planStatus,
|
||||||
|
String detailResource,
|
||||||
|
String requiredPermission
|
||||||
|
) {
|
||||||
|
}
|
||||||
|
|
||||||
public record PreloadSummary(
|
public record PreloadSummary(
|
||||||
Long planId,
|
Long planId,
|
||||||
Long containerBookingId,
|
Long containerBookingId,
|
||||||
|
|||||||
@@ -16,6 +16,7 @@ import com.baiyue.firstleg.dto.LoadingListDtos.TransportUpdateRequest;
|
|||||||
import com.baiyue.firstleg.dto.LoadingListDtos.BusinessDocument;
|
import com.baiyue.firstleg.dto.LoadingListDtos.BusinessDocument;
|
||||||
import com.baiyue.firstleg.dto.LoadingListDtos.DocumentAttachRequest;
|
import com.baiyue.firstleg.dto.LoadingListDtos.DocumentAttachRequest;
|
||||||
import com.baiyue.firstleg.dto.LoadingListDtos.DocumentCompleteRequest;
|
import com.baiyue.firstleg.dto.LoadingListDtos.DocumentCompleteRequest;
|
||||||
|
import com.baiyue.firstleg.dto.LoadingListDtos.LifecycleResolution;
|
||||||
import com.baiyue.firstleg.client.LoadingDocumentFileClient;
|
import com.baiyue.firstleg.client.LoadingDocumentFileClient;
|
||||||
import com.baiyue.firstleg.entity.ContainerDocumentEntity;
|
import com.baiyue.firstleg.entity.ContainerDocumentEntity;
|
||||||
import com.baiyue.firstleg.mapper.LoadingListQueryMapper.AggregateRow;
|
import com.baiyue.firstleg.mapper.LoadingListQueryMapper.AggregateRow;
|
||||||
@@ -97,20 +98,38 @@ public class LoadingListService {
|
|||||||
AggregateRow row = requirePlan(planId);
|
AggregateRow row = requirePlan(planId);
|
||||||
requireWarehouse(row, warehouseId);
|
requireWarehouse(row, warehouseId);
|
||||||
if (!PRELOAD_STATUSES.contains(row.getPlanStatus())) {
|
if (!PRELOAD_STATUSES.contains(row.getPlanStatus())) {
|
||||||
throw notFound("预装清单不存在");
|
throw conflict("装柜计划已离开预装详情阶段");
|
||||||
}
|
}
|
||||||
return repository.preloadDetail(row);
|
return repository.preloadDetail(row);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public LifecycleResolution lifecycle(long planId, long warehouseId) {
|
||||||
|
AggregateRow row = requirePlan(planId);
|
||||||
|
requireWarehouse(row, warehouseId);
|
||||||
|
if (PRELOAD_STATUSES.contains(row.getPlanStatus())) {
|
||||||
|
return lifecycle(row, "PRELOAD", "platform:firstleg:preload:list");
|
||||||
|
}
|
||||||
|
if ("COMPLETED".equals(row.getPlanStatus())) {
|
||||||
|
return lifecycle(row, "LOADING_LIST", "platform:firstleg:loading-list:list");
|
||||||
|
}
|
||||||
|
throw conflict("装柜计划处于未知生命周期阶段");
|
||||||
|
}
|
||||||
|
|
||||||
public ConfirmedDetail confirmedDetail(long planId, long warehouseId) {
|
public ConfirmedDetail confirmedDetail(long planId, long warehouseId) {
|
||||||
AggregateRow row = requirePlan(planId);
|
AggregateRow row = requirePlan(planId);
|
||||||
requireWarehouse(row, warehouseId);
|
requireWarehouse(row, warehouseId);
|
||||||
if (!"COMPLETED".equals(row.getPlanStatus())) {
|
if (!"COMPLETED".equals(row.getPlanStatus())) {
|
||||||
throw notFound("装柜清单不存在");
|
throw conflict("装柜计划尚未进入正式装柜清单阶段");
|
||||||
}
|
}
|
||||||
return repository.confirmedDetail(row);
|
return repository.confirmedDetail(row);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static LifecycleResolution lifecycle(AggregateRow row, String resource,
|
||||||
|
String permission) {
|
||||||
|
return new LifecycleResolution(row.getPlanId(), row.getContainerBookingId(),
|
||||||
|
row.getWarehouseId(), row.getPlanNo(), row.getPlanStatus(), resource, permission);
|
||||||
|
}
|
||||||
|
|
||||||
public BusinessDocument containerClearance(long bookingId) {
|
public BusinessDocument containerClearance(long bookingId) {
|
||||||
requireBookingPlan(bookingId);
|
requireBookingPlan(bookingId);
|
||||||
return document(repository.document(bookingId, DESTINATION_CLEARANCE));
|
return document(repository.document(bookingId, DESTINATION_CLEARANCE));
|
||||||
@@ -554,7 +573,7 @@ public class LoadingListService {
|
|||||||
throw badRequest("warehouseId必须大于0");
|
throw badRequest("warehouseId必须大于0");
|
||||||
}
|
}
|
||||||
if (!java.util.Objects.equals(row.getWarehouseId(), warehouseId)) {
|
if (!java.util.Objects.equals(row.getWarehouseId(), warehouseId)) {
|
||||||
throw notFound("装柜计划不属于当前仓库");
|
throw new BizException(ResultCode.FORBIDDEN, "装柜计划不属于当前仓库");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -31,6 +31,20 @@ paths:
|
|||||||
parameters: [{$ref: '#/components/parameters/PlanId'}, {$ref: '#/components/parameters/WarehouseId'}]
|
parameters: [{$ref: '#/components/parameters/PlanId'}, {$ref: '#/components/parameters/WarehouseId'}]
|
||||||
responses:
|
responses:
|
||||||
'200': {$ref: '#/components/responses/PreloadDetailResponse'}
|
'200': {$ref: '#/components/responses/PreloadDetailResponse'}
|
||||||
|
'409': {description: 计划已离开预装阶段;先查询 lifecycle 获取当前正式详情资源}
|
||||||
|
/api/platform/v1/first-leg/loading-plans/{planId}/lifecycle:
|
||||||
|
get:
|
||||||
|
summary: 解析装柜计划当前详情阶段
|
||||||
|
description: >-
|
||||||
|
需要 platform:firstleg:preload:list 权限。同一 planId 从 EDITING、LOADING 到 COMPLETED 永久稳定;
|
||||||
|
EDITING/LOADING 返回 PRELOAD,COMPLETED 返回 LOADING_LIST 及其独立读取权限。
|
||||||
|
页面据此选择预装详情或正式装柜清单详情,不得以错误文案或 A0404 猜测阶段。
|
||||||
|
x-permission: platform:firstleg:preload:list
|
||||||
|
parameters: [{$ref: '#/components/parameters/PlanId'}, {$ref: '#/components/parameters/WarehouseId'}]
|
||||||
|
responses:
|
||||||
|
'200': {$ref: '#/components/responses/LifecycleResolutionResponse'}
|
||||||
|
'403': {description: planId 不属于请求仓库或缺少平台读取权限}
|
||||||
|
'404': {description: planId 真实不存在}
|
||||||
/api/platform/v1/first-leg/loading-plans/{planId}/transport:
|
/api/platform/v1/first-leg/loading-plans/{planId}/transport:
|
||||||
patch:
|
patch:
|
||||||
summary: 修改预装运输信息
|
summary: 修改预装运输信息
|
||||||
@@ -83,6 +97,7 @@ paths:
|
|||||||
parameters: [{$ref: '#/components/parameters/PlanId'}, {$ref: '#/components/parameters/WarehouseId'}]
|
parameters: [{$ref: '#/components/parameters/PlanId'}, {$ref: '#/components/parameters/WarehouseId'}]
|
||||||
responses:
|
responses:
|
||||||
'200': {$ref: '#/components/responses/ConfirmedDetailResponse'}
|
'200': {$ref: '#/components/responses/ConfirmedDetailResponse'}
|
||||||
|
'409': {description: 计划尚未进入 COMPLETED 正式装柜清单阶段}
|
||||||
components:
|
components:
|
||||||
parameters:
|
parameters:
|
||||||
PlanId:
|
PlanId:
|
||||||
@@ -156,6 +171,9 @@ components:
|
|||||||
ConfirmedDetailResponse:
|
ConfirmedDetailResponse:
|
||||||
description: 装柜清单详情查询或确认成功,也可能返回业务失败
|
description: 装柜清单详情查询或确认成功,也可能返回业务失败
|
||||||
content: {application/json: {schema: {$ref: '#/components/schemas/ConfirmedDetailEnvelope'}}}
|
content: {application/json: {schema: {$ref: '#/components/schemas/ConfirmedDetailEnvelope'}}}
|
||||||
|
LifecycleResolutionResponse:
|
||||||
|
description: 装柜计划生命周期解析成功或业务失败
|
||||||
|
content: {application/json: {schema: {$ref: '#/components/schemas/LifecycleResolutionEnvelope'}}}
|
||||||
schemas:
|
schemas:
|
||||||
LongId:
|
LongId:
|
||||||
type: string
|
type: string
|
||||||
@@ -214,6 +232,14 @@ components:
|
|||||||
data:
|
data:
|
||||||
allOf: [{$ref: '#/components/schemas/ConfirmedDetail'}]
|
allOf: [{$ref: '#/components/schemas/ConfirmedDetail'}]
|
||||||
nullable: true
|
nullable: true
|
||||||
|
LifecycleResolutionEnvelope:
|
||||||
|
allOf:
|
||||||
|
- {$ref: '#/components/schemas/ApiEnvelope'}
|
||||||
|
- type: object
|
||||||
|
properties:
|
||||||
|
data:
|
||||||
|
allOf: [{$ref: '#/components/schemas/LifecycleResolution'}]
|
||||||
|
nullable: true
|
||||||
PreloadPage:
|
PreloadPage:
|
||||||
type: object
|
type: object
|
||||||
required: [records, page, size, total, pages]
|
required: [records, page, size, total, pages]
|
||||||
@@ -238,6 +264,18 @@ components:
|
|||||||
properties:
|
properties:
|
||||||
accountId: {$ref: '#/components/schemas/LongId'}
|
accountId: {$ref: '#/components/schemas/LongId'}
|
||||||
customerName: {type: string, nullable: true, description: 客户名称}
|
customerName: {type: string, nullable: true, description: 客户名称}
|
||||||
|
LifecycleResolution:
|
||||||
|
type: object
|
||||||
|
additionalProperties: false
|
||||||
|
required: [planId, containerBookingId, warehouseId, planNo, planStatus, detailResource, requiredPermission]
|
||||||
|
properties:
|
||||||
|
planId: {$ref: '#/components/schemas/LongId'}
|
||||||
|
containerBookingId: {$ref: '#/components/schemas/LongId'}
|
||||||
|
warehouseId: {$ref: '#/components/schemas/LongId'}
|
||||||
|
planNo: {type: string, description: 预装与正式装柜清单沿用的稳定业务号}
|
||||||
|
planStatus: {type: string, enum: [EDITING, LOADING, COMPLETED]}
|
||||||
|
detailResource: {type: string, enum: [PRELOAD, LOADING_LIST], description: 当前应读取的唯一详情资源}
|
||||||
|
requiredPermission: {type: string, enum: ['platform:firstleg:preload:list', 'platform:firstleg:loading-list:list']}
|
||||||
PreloadSummary:
|
PreloadSummary:
|
||||||
type: object
|
type: object
|
||||||
required: [planId, containerBookingId, preloadNo, customers, status, skuCount, totalPackageCount, totalVolumeCbm, totalGrossWeightKg, createdAt, version, readiness]
|
required: [planId, containerBookingId, preloadNo, customers, status, skuCount, totalPackageCount, totalVolumeCbm, totalGrossWeightKg, createdAt, version, readiness]
|
||||||
|
|||||||
+9
-1
@@ -29,6 +29,7 @@ class LoadingListControllerContractTest {
|
|||||||
void permissionsMatch() throws Exception {
|
void permissionsMatch() throws Exception {
|
||||||
authority("preloadPage", "platform:firstleg:preload:list", AuthenticatedUser.class, PreloadQuery.class);
|
authority("preloadPage", "platform:firstleg:preload:list", AuthenticatedUser.class, PreloadQuery.class);
|
||||||
authority("preloadDetail", "platform:firstleg:preload:list", AuthenticatedUser.class, long.class, long.class);
|
authority("preloadDetail", "platform:firstleg:preload:list", AuthenticatedUser.class, long.class, long.class);
|
||||||
|
authority("lifecycle", "platform:firstleg:preload:list", AuthenticatedUser.class, long.class, long.class);
|
||||||
authority("updateTransport", "platform:firstleg:preload:edit", AuthenticatedUser.class,
|
authority("updateTransport", "platform:firstleg:preload:edit", AuthenticatedUser.class,
|
||||||
long.class, long.class, String.class, TransportUpdateRequest.class);
|
long.class, long.class, String.class, TransportUpdateRequest.class);
|
||||||
authority("confirmPreload", "platform:firstleg:preload:edit", AuthenticatedUser.class,
|
authority("confirmPreload", "platform:firstleg:preload:edit", AuthenticatedUser.class,
|
||||||
@@ -72,6 +73,8 @@ class LoadingListControllerContractTest {
|
|||||||
.contains("校验ISO 6346结构、设备类别和校验位")
|
.contains("校验ISO 6346结构、设备类别和校验位")
|
||||||
.contains("PDA任务尚未领取且无任何物理作业事实")
|
.contains("PDA任务尚未领取且无任何物理作业事实")
|
||||||
.contains("/loading-plans/{planId}/confirm")
|
.contains("/loading-plans/{planId}/confirm")
|
||||||
|
.contains("/loading-plans/{planId}/lifecycle")
|
||||||
|
.contains("不得以错误文案或 A0404 猜测阶段")
|
||||||
.contains("confirmationStatus")
|
.contains("confirmationStatus")
|
||||||
.contains("canConfirm")
|
.contains("canConfirm")
|
||||||
.contains("blockingReasons")
|
.contains("blockingReasons")
|
||||||
@@ -116,6 +119,7 @@ class LoadingListControllerContractTest {
|
|||||||
assertThat(paths).containsOnlyKeys(
|
assertThat(paths).containsOnlyKeys(
|
||||||
"/api/platform/v1/first-leg/loading-plans",
|
"/api/platform/v1/first-leg/loading-plans",
|
||||||
"/api/platform/v1/first-leg/loading-plans/{planId}",
|
"/api/platform/v1/first-leg/loading-plans/{planId}",
|
||||||
|
"/api/platform/v1/first-leg/loading-plans/{planId}/lifecycle",
|
||||||
"/api/platform/v1/first-leg/loading-plans/{planId}/transport",
|
"/api/platform/v1/first-leg/loading-plans/{planId}/transport",
|
||||||
"/api/platform/v1/first-leg/loading-plans/{planId}/confirm",
|
"/api/platform/v1/first-leg/loading-plans/{planId}/confirm",
|
||||||
"/api/platform/v1/first-leg/loading-lists",
|
"/api/platform/v1/first-leg/loading-lists",
|
||||||
@@ -126,7 +130,11 @@ class LoadingListControllerContractTest {
|
|||||||
"LongId", "PreloadPage", "ConfirmedPage", "Customer", "PreloadSummary",
|
"LongId", "PreloadPage", "ConfirmedPage", "Customer", "PreloadSummary",
|
||||||
"ConfirmedSummary", "LoadingItem", "OperationHistory", "PreloadDetail",
|
"ConfirmedSummary", "LoadingItem", "OperationHistory", "PreloadDetail",
|
||||||
"ConfirmedDetail", "TransportUpdateRequest", "PreloadReadiness",
|
"ConfirmedDetail", "TransportUpdateRequest", "PreloadReadiness",
|
||||||
"ConfirmPreloadRequest", "PreloadConfirmation", "PreloadConfirmationEnvelope");
|
"ConfirmPreloadRequest", "PreloadConfirmation", "PreloadConfirmationEnvelope",
|
||||||
|
"LifecycleResolution", "LifecycleResolutionEnvelope");
|
||||||
|
assertThat(properties(schemas, "LifecycleResolution")).containsOnlyKeys(
|
||||||
|
"planId", "containerBookingId", "warehouseId", "planNo", "planStatus",
|
||||||
|
"detailResource", "requiredPermission");
|
||||||
assertThat(paths)
|
assertThat(paths)
|
||||||
.doesNotContainKey("/api/platform/v1/first-leg/loading-plans/{planId}/complete");
|
.doesNotContainKey("/api/platform/v1/first-leg/loading-plans/{planId}/complete");
|
||||||
assertThat(stringMap(schemas.get("LongId"))).containsEntry("type", "string");
|
assertThat(stringMap(schemas.get("LongId"))).containsEntry("type", "string");
|
||||||
|
|||||||
+9
@@ -67,6 +67,15 @@ class LoadingListQueryMapperContractTest {
|
|||||||
.contains("i.deleted = 0");
|
.contains("i.deleted = 0");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void lifecycleAggregateKeepsTheSamePlanIdAcrossEveryStatus() throws Exception {
|
||||||
|
String aggregate = sql("selectAggregate", Select.class);
|
||||||
|
assertThat(aggregate)
|
||||||
|
.contains("WHERE p.id = #{planId}")
|
||||||
|
.contains("p.plan_status")
|
||||||
|
.doesNotContain("plan_status = 'COMPLETED'", "plan_status IN ('EDITING', 'LOADING')");
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
void mutationsShouldUseStatusAndOptimisticVersionConditions() throws Exception {
|
void mutationsShouldUseStatusAndOptimisticVersionConditions() throws Exception {
|
||||||
String touch = sql("touchEditable", Update.class);
|
String touch = sql("touchEditable", Update.class);
|
||||||
|
|||||||
@@ -361,7 +361,42 @@ class LoadingListServiceTest {
|
|||||||
assertThatThrownBy(() -> service.preloadDetail(10L, 200L))
|
assertThatThrownBy(() -> service.preloadDetail(10L, 200L))
|
||||||
.isInstanceOf(BizException.class)
|
.isInstanceOf(BizException.class)
|
||||||
.extracting(error -> ((BizException) error).getResultCode())
|
.extracting(error -> ((BizException) error).getResultCode())
|
||||||
.isEqualTo(ResultCode.NOT_FOUND);
|
.isEqualTo(ResultCode.FORBIDDEN);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void resolvesStablePlanIdToPreloadOrCompletedLoadingListWithoutGuessingFrom404() {
|
||||||
|
when(repository.aggregate(10L)).thenReturn(row("LOADING", 2), row("COMPLETED", 3));
|
||||||
|
|
||||||
|
var preload = service.lifecycle(10L, 100L);
|
||||||
|
var completed = service.lifecycle(10L, 100L);
|
||||||
|
|
||||||
|
assertThat(preload.planId()).isEqualTo(10L);
|
||||||
|
assertThat(preload.planStatus()).isEqualTo("LOADING");
|
||||||
|
assertThat(preload.detailResource()).isEqualTo("PRELOAD");
|
||||||
|
assertThat(preload.requiredPermission()).isEqualTo("platform:firstleg:preload:list");
|
||||||
|
assertThat(completed.planId()).isEqualTo(10L);
|
||||||
|
assertThat(completed.planStatus()).isEqualTo("COMPLETED");
|
||||||
|
assertThat(completed.detailResource()).isEqualTo("LOADING_LIST");
|
||||||
|
assertThat(completed.requiredPermission()).isEqualTo("platform:firstleg:loading-list:list");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void stageMismatchIsConflictAndOnlyMissingPlanIsNotFound() {
|
||||||
|
when(repository.aggregate(10L)).thenReturn(row("COMPLETED", 3));
|
||||||
|
assertThatThrownBy(() -> service.preloadDetail(10L, 100L))
|
||||||
|
.isInstanceOfSatisfying(BizException.class, error ->
|
||||||
|
assertThat(error.getResultCode()).isEqualTo(ResultCode.CONFLICT));
|
||||||
|
|
||||||
|
when(repository.aggregate(11L)).thenReturn(row("LOADING", 2));
|
||||||
|
assertThatThrownBy(() -> service.confirmedDetail(11L, 100L))
|
||||||
|
.isInstanceOfSatisfying(BizException.class, error ->
|
||||||
|
assertThat(error.getResultCode()).isEqualTo(ResultCode.CONFLICT));
|
||||||
|
|
||||||
|
when(repository.aggregate(12L)).thenReturn(null);
|
||||||
|
assertThatThrownBy(() -> service.lifecycle(12L, 100L))
|
||||||
|
.isInstanceOfSatisfying(BizException.class, error ->
|
||||||
|
assertThat(error.getResultCode()).isEqualTo(ResultCode.NOT_FOUND));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
|||||||
Reference in New Issue
Block a user