Files
baiyue-firstleg/firstleg/src/test/java/com/baiyue/firstleg/controller/InboundMeasurementReviewContractTest.java
T
2026-10-21 07:53:31 +08:00

88 lines
4.8 KiB
Java

package com.baiyue.firstleg.controller;
import com.baiyue.common.security.AuthenticatedUser;
import com.baiyue.firstleg.dto.MeasurementApprovalResponse;
import com.baiyue.firstleg.dto.MeasurementReviewRequest;
import com.baiyue.firstleg.service.InitialInboundPricingService;
import com.baiyue.firstleg.service.MeasurementReviewService;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
import org.springframework.core.io.ClassPathResource;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.test.util.ReflectionTestUtils;
import java.lang.reflect.Method;
import java.nio.charset.StandardCharsets;
import java.util.Set;
import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.Mockito.inOrder;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
@DisplayName("入库测量审核控制器契约")
class InboundMeasurementReviewContractTest {
@Test
@DisplayName("审核和历史接口声明独立按钮权限")
void shouldDeclareButtonPermissions() throws Exception {
assertAuthority("approve", "hasAuthority('firstleg:inbound:measurement-review')",
AuthenticatedUser.class, long.class, long.class, String.class, MeasurementReviewRequest.class);
assertAuthority("history", "hasAuthority('firstleg:inbound:measurement-review-history')",
AuthenticatedUser.class, long.class, long.class, long.class, long.class);
}
@Test
@DisplayName("测量审核不进入待客户确认,并声明幂等和字符串长ID")
void shouldDocumentReviewContract() throws Exception {
String openapi = new ClassPathResource("openapi/firstleg-v1.yaml")
.getContentAsString(StandardCharsets.UTF_8);
assertThat(openapi)
.contains("/api/platform/v1/inbounds/{inboundId}/measurements/approve:")
.contains("Idempotency-Key")
.contains("初算异常只返回非阻断提示")
.contains("标准头程审核通过后进入 WAIT_SPLIT")
.contains("一件代发进入 WAIT_PALLETIZE")
.contains("feeStatus=UNPRICED 且主流程仍成功")
.contains("name: inboundId")
.contains("schema: {type: string, pattern:")
.doesNotContain("/api/platform/v1/inbounds/{inboundId}/measurements/reject:")
.doesNotContain("/api/platform/v1/inbounds/{inboundId}/measurements/exception-release:");
// 约束仅针对测量审核;客户费用确认属于另一业务,允许独立存在。
int start = openapi.indexOf(" /api/platform/v1/inbounds/{inboundId}/measurements/approve:");
int end = openapi.indexOf("\n /", start + 1);
assertThat(openapi.substring(start, end < 0 ? openapi.length() : end)).doesNotContain("待客户确认");
}
@Test
@DisplayName("审核先提交待分柜,再执行不阻塞的初算")
void shouldApproveBeforeBestEffortInitialPricing() {
MeasurementReviewService review = mock(MeasurementReviewService.class);
InitialInboundPricingService initialPricing = mock(InitialInboundPricingService.class);
PlatformInboundMeasurementReviewController controller = new PlatformInboundMeasurementReviewController();
ReflectionTestUtils.setField(controller, "service", review);
ReflectionTestUtils.setField(controller, "initialPricing", initialPricing);
AuthenticatedUser user = new AuthenticatedUser(9L, 0L, 0L, null,
"客服", "PLATFORM", "WEB", Set.of("firstleg:inbound:measurement-review"));
MeasurementReviewRequest request = new MeasurementReviewRequest(30L, 4, "通过");
var result = new MeasurementApprovalResponse(88L, 30L, "WAIT_SPLIT", "UNPRICED",
false, "待人工维护费用", null);
when(initialPricing.tryCalculate(10001L, 9L, 88L, 30L, 5)).thenReturn(result);
var first = controller.approve(user, 10001L, 88L, "approve-1", request);
var replay = controller.approve(user, 10001L, 88L, "approve-1", request);
assertThat(first.data()).isSameAs(result);
assertThat(replay.data()).isSameAs(result);
var ordered = inOrder(review, initialPricing);
ordered.verify(review).approve(10001L, 9L, "客服", 88L, "approve-1", request);
ordered.verify(initialPricing).tryCalculate(10001L, 9L, 88L, 30L, 5);
ordered.verify(review).approve(10001L, 9L, "客服", 88L, "approve-1", request);
ordered.verify(initialPricing).tryCalculate(10001L, 9L, 88L, 30L, 5);
}
private void assertAuthority(String name, String expression, Class<?>... types) throws Exception {
Method method = PlatformInboundMeasurementReviewController.class.getDeclaredMethod(name, types);
assertThat(method.getAnnotation(PreAuthorize.class).value()).isEqualTo(expression);
}
}