2026-08-04 10:07:45 +08:00
|
|
|
package com.baiyue.firstleg.controller;
|
|
|
|
|
|
|
|
|
|
import org.junit.jupiter.api.DisplayName;
|
|
|
|
|
import org.junit.jupiter.api.Test;
|
|
|
|
|
import org.springframework.core.io.ClassPathResource;
|
2026-08-05 09:11:26 +08:00
|
|
|
import org.springframework.web.bind.annotation.RequestParam;
|
2026-08-04 10:07:45 +08:00
|
|
|
|
|
|
|
|
import java.nio.charset.StandardCharsets;
|
2026-08-05 09:11:26 +08:00
|
|
|
import java.lang.reflect.Method;
|
2026-08-04 10:07:45 +08:00
|
|
|
|
|
|
|
|
import static org.assertj.core.api.Assertions.assertThat;
|
|
|
|
|
|
|
|
|
|
@DisplayName("FBA计费OpenAPI契约")
|
|
|
|
|
class FbaPricingContractTest {
|
2026-08-05 09:11:26 +08:00
|
|
|
@Test
|
2026-08-06 18:01:59 +08:00
|
|
|
@DisplayName("客户规则保留客户参数,船司价格使用平台公共作用域")
|
|
|
|
|
void keepsCustomerRuleScopeAndRemovesCarrierRateTenantScope() {
|
|
|
|
|
Method rules = method("rules");
|
|
|
|
|
assertThat(rules.getParameterTypes()[1]).isEqualTo(Long.class);
|
|
|
|
|
assertThat(rules.getParameters()[1].getAnnotation(RequestParam.class).required()).isFalse();
|
2026-08-05 09:11:26 +08:00
|
|
|
|
2026-08-06 18:01:59 +08:00
|
|
|
Method rates = method("rates");
|
|
|
|
|
assertThat(rates.getParameterTypes()).doesNotContain(Long.class);
|
|
|
|
|
|
|
|
|
|
for (String scopedMethod : new String[] {"rule", "createRule", "retireRule"}) {
|
2026-08-05 09:11:26 +08:00
|
|
|
Method method = method(scopedMethod);
|
|
|
|
|
assertThat(method.getParameterTypes()[1]).isEqualTo(long.class);
|
|
|
|
|
assertThat(method.getParameters()[1].getAnnotation(RequestParam.class).required()).isTrue();
|
|
|
|
|
}
|
2026-08-06 18:01:59 +08:00
|
|
|
|
|
|
|
|
for (String publicMethod : new String[] {"rate", "createRate", "retireRate"}) {
|
|
|
|
|
assertThat(java.util.Arrays.stream(method(publicMethod).getParameters())
|
|
|
|
|
.map(parameter -> parameter.getAnnotation(RequestParam.class)))
|
|
|
|
|
.allMatch(annotation -> annotation == null);
|
|
|
|
|
}
|
2026-08-05 09:11:26 +08:00
|
|
|
}
|
|
|
|
|
|
2026-08-04 10:07:45 +08:00
|
|
|
@Test
|
2026-08-06 18:34:52 +08:00
|
|
|
@DisplayName("契约声明二期边界计费、已发布费用调整和幂等头")
|
2026-08-04 10:07:45 +08:00
|
|
|
void documentsPricingLifecycle() throws Exception {
|
|
|
|
|
String openapi = new ClassPathResource("openapi/fba-pricing-v1.yaml")
|
|
|
|
|
.getContentAsString(StandardCharsets.UTF_8);
|
|
|
|
|
assertThat(openapi)
|
|
|
|
|
.contains("/api/platform/v1/fba-pricing/customer-rules/versions:")
|
|
|
|
|
.contains("/api/platform/v1/fba-pricing/carrier-rates/versions:")
|
|
|
|
|
.contains("/api/platform/v1/inbounds/{inboundId}/fees/calculate:")
|
|
|
|
|
.contains("/api/platform/v1/inbounds/{inboundId}/fees/confirm:")
|
|
|
|
|
.contains("/api/platform/v1/inbounds/{inboundId}/fees/send:")
|
|
|
|
|
.contains("/api/platform/v1/inbounds/{inboundId}/fees/published:")
|
|
|
|
|
.contains("Idempotency-Key")
|
2026-08-13 14:37:51 +08:00
|
|
|
.contains("主流程已到 WAIT_SPLIT,也可独立试算且不回退主流程状态")
|
2026-08-14 12:50:37 +08:00
|
|
|
.contains("区域阶梯渠道可按平台 FBA 仓或海外中转仓的邮编区域")
|
|
|
|
|
.contains("不再以 carrierId、业务 customerId 或客户计费规则作为前置")
|
2026-08-06 18:34:52 +08:00
|
|
|
.contains("该动作涉及后续仓储流程,本轮二期验收不调用")
|
2026-08-13 14:37:51 +08:00
|
|
|
.contains("不回退 WAIT_SPLIT 状态")
|
2026-08-04 10:07:45 +08:00
|
|
|
.doesNotContain("应收")
|
|
|
|
|
.doesNotContain("应付")
|
|
|
|
|
.doesNotContain("待客户确认");
|
2026-08-05 09:11:26 +08:00
|
|
|
String customerRules = openapi.substring(
|
|
|
|
|
openapi.indexOf("/api/platform/v1/fba-pricing/customer-rules:"),
|
|
|
|
|
openapi.indexOf("/api/platform/v1/fba-pricing/customer-rules/versions:"));
|
|
|
|
|
assertThat(customerRules)
|
|
|
|
|
.contains("OptionalTenantId")
|
|
|
|
|
.contains("name: ruleCode")
|
|
|
|
|
.doesNotContain("#/components/parameters/Page")
|
|
|
|
|
.doesNotContain("#/components/parameters/Size")
|
|
|
|
|
.doesNotContain("name: customerName")
|
|
|
|
|
.doesNotContain("name: chargeMode")
|
|
|
|
|
.doesNotContain("name: status");
|
2026-08-05 09:30:08 +08:00
|
|
|
String carrierRates = openapi.substring(
|
|
|
|
|
openapi.indexOf("/api/platform/v1/fba-pricing/carrier-rates:"),
|
|
|
|
|
openapi.indexOf("/api/platform/v1/fba-pricing/carrier-rates/versions:"));
|
|
|
|
|
assertThat(carrierRates)
|
2026-08-06 18:01:59 +08:00
|
|
|
.doesNotContain("OptionalTenantId")
|
2026-08-05 09:30:08 +08:00
|
|
|
.contains("name: rateCode");
|
2026-08-05 09:11:26 +08:00
|
|
|
assertThat(openapi)
|
|
|
|
|
.contains("OptionalTenantId: {name: tenantId, in: query, required: false")
|
|
|
|
|
.contains("schema: {type: string, pattern: '^[1-9][0-9]*$'}")
|
|
|
|
|
.doesNotContain("format: int64");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private static Method method(String name) {
|
|
|
|
|
return java.util.Arrays.stream(PlatformFbaMasterDataController.class.getDeclaredMethods())
|
|
|
|
|
.filter(candidate -> candidate.getName().equals(name))
|
|
|
|
|
.findFirst().orElseThrow();
|
2026-08-04 10:07:45 +08:00
|
|
|
}
|
|
|
|
|
}
|