fix(firstleg): align merchant billing with sent fees

This commit is contained in:
2026-08-29 11:13:35 +08:00
parent b4db37392d
commit de101621dd
5 changed files with 13 additions and 13 deletions
@@ -30,7 +30,7 @@ public class MerchantInboundBillingController {
@PreAuthorize("hasAuthority('merchant:order:view')")
@Operation(summary = "查询订单入库结果和最新费用",
description = "客户按登录态客户范围只读查看;入库流程达到 WAIT_SPLIT 后,"
+ "在 LOADING、LOADED、DELIVERED 仍持续可见,且始终要求 APPROVED + CONFIRMED "
+ "在 LOADING、LOADED、DELIVERED 仍持续可见,且始终要求 APPROVED + SENT "
+ "并存在已发布入库运费明细,不需要客户确认费用。")
public ApiResponse<MerchantInboundBillingResponse> find(
@AuthenticationPrincipal AuthenticatedUser user, @PathVariable long orderId) {
@@ -126,7 +126,7 @@ public class MerchantInboundBillingService {
private static boolean isPublished(InboundOrderEntity inbound) {
return PUBLISHED_BILLING_PROCESS_STATUSES.contains(inbound.getProcessStatus())
&& "APPROVED".equals(inbound.getMeasureReviewStatus())
&& "CONFIRMED".equals(inbound.getFeeStatus());
&& "SENT".equals(inbound.getFeeStatus());
}
private String previewUrl(long orderId, long fileId) {
@@ -905,7 +905,7 @@ paths:
/api/merchant/v1/first-leg/orders/{orderId}/inbound-billing:
get:
summary: 客户查询已完成入库结果和最新已发布费用
description: 需要 merchant:order:view 权限;客户仅能按登录态客户范围只读查看。入库流程达到 WAIT_SPLIT 后,费用在 LOADING、LOADED、DELIVERED 仍持续可见;始终要求 measureReviewStatus=APPROVED、feeStatus=CONFIRMED 且存在 PUBLISHED 入库运费明细,不需要客户确认费用。
description: 需要 merchant:order:view 权限;客户仅能按登录态客户范围只读查看。入库流程达到 WAIT_SPLIT 后,费用在 LOADING、LOADED、DELIVERED 仍持续可见;始终要求 measureReviewStatus=APPROVED、feeStatus=SENT 且存在 PUBLISHED 入库运费明细,不需要客户确认费用。CONFIRMED 只表示发送前确认完成,尚未生成可对客发布明细。
parameters:
- {name: orderId, in: path, required: true, schema: {type: string, pattern: '^[1-9][0-9]*$'}}
responses:
@@ -34,7 +34,7 @@ class MerchantInboundBillingControllerContractTest {
assertThat(method.getAnnotation(PreAuthorize.class).value())
.isEqualTo("hasAuthority('merchant:order:view')");
assertThat(method.getAnnotation(Operation.class).description())
.contains("WAIT_SPLIT", "LOADING", "LOADED", "DELIVERED", "APPROVED + CONFIRMED", "已发布入库运费明细");
.contains("WAIT_SPLIT", "LOADING", "LOADED", "DELIVERED", "APPROVED + SENT", "已发布入库运费明细");
assertThat(MerchantInboundBillingController.class.getDeclaredMethods())
.noneMatch(candidate -> candidate.getName().toLowerCase().contains("confirm"));
@@ -42,7 +42,7 @@ class MerchantInboundBillingControllerContractTest {
.getContentAsString(StandardCharsets.UTF_8);
assertThat(openapi).contains("/api/merchant/v1/first-leg/orders/{orderId}/inbound-billing:")
.contains("WAIT_SPLIT", "LOADING、LOADED、DELIVERED", "measureReviewStatus=APPROVED",
"feeStatus=CONFIRMED", "PUBLISHED 入库运费明细");
"feeStatus=SENT", "PUBLISHED 入库运费明细", "CONFIRMED 只表示发送前确认完成");
}
@Test
@@ -39,7 +39,7 @@ class MerchantInboundBillingServiceTest {
@ParameterizedTest
@ValueSource(strings = {"WAIT_SPLIT", "LOADING", "LOADED", "DELIVERED"})
void shouldKeepPublishedBillingVisibleAfterFulfillmentProgresses(String processStatus) {
InboundOrderEntity inbound = inbound(processStatus, "APPROVED", "CONFIRMED");
InboundOrderEntity inbound = inbound(processStatus, "APPROVED", "SENT");
InboundOrderDetail detail = new InboundOrderDetail(mock(com.baiyue.firstleg.dto.InboundOrderSummary.class),
"客户备注", List.of(), List.of(
new InboundOrderDetail.FileSummary(1L, "RELATED", "public.pdf", "PUBLIC", 1, 1L, null),
@@ -86,7 +86,7 @@ class MerchantInboundBillingServiceTest {
@Test
void shouldHandleCase02() {
InboundOrderEntity inbound = inbound("WAIT_SPLIT", "PENDING", "CONFIRMED");
InboundOrderEntity inbound = inbound("WAIT_SPLIT", "PENDING", "SENT");
when(orders.findByOrderId(10001L, 77L)).thenReturn(inbound);
assertThatThrownBy(() -> service.find(10001L, 77L))
@@ -107,7 +107,7 @@ class MerchantInboundBillingServiceTest {
@Test
void shouldHandleCase04() {
InboundOrderEntity inbound = inbound("WAIT_SPLIT", "APPROVED", "CONFIRMED");
InboundOrderEntity inbound = inbound("WAIT_SPLIT", "APPROVED", "SENT");
InboundMeasurementResponses.Detail measurement = mock(InboundMeasurementResponses.Detail.class);
InboundMeasurementResponses.Item item = mock(InboundMeasurementResponses.Item.class);
when(item.intelligentImageFileId()).thenReturn(41L);
@@ -130,7 +130,7 @@ class MerchantInboundBillingServiceTest {
@Test
void shouldHandleCase05() {
InboundOrderEntity inbound = inbound("WAIT_SPLIT", "APPROVED", "CONFIRMED");
InboundOrderEntity inbound = inbound("WAIT_SPLIT", "APPROVED", "SENT");
InboundMeasurementResponses.Detail measurement = mock(InboundMeasurementResponses.Detail.class);
when(measurement.items()).thenReturn(List.of());
when(measurement.weightResults()).thenReturn(List.of());
@@ -144,8 +144,8 @@ class MerchantInboundBillingServiceTest {
}
@Test
void shouldRejectHistoricalPublishedStatusCombination() {
InboundOrderEntity inbound = inbound("WAIT_SPLIT", "APPROVED", "SENT");
void shouldRejectConfirmedFeeBeforeItIsSentAndPublished() {
InboundOrderEntity inbound = inbound("WAIT_SPLIT", "APPROVED", "CONFIRMED");
when(orders.findByOrderId(10001L, 77L)).thenReturn(inbound);
assertThatThrownBy(() -> service.find(10001L, 77L))
@@ -157,7 +157,7 @@ class MerchantInboundBillingServiceTest {
@ParameterizedTest
@ValueSource(strings = {"FEE_CONFIRMING", "VOIDED"})
void shouldRejectProcessStatusesOutsidePublishedFulfillmentLifecycle(String processStatus) {
InboundOrderEntity inbound = inbound(processStatus, "APPROVED", "CONFIRMED");
InboundOrderEntity inbound = inbound(processStatus, "APPROVED", "SENT");
when(orders.findByOrderId(10001L, 77L)).thenReturn(inbound);
assertThatThrownBy(() -> service.find(10001L, 77L))
@@ -168,7 +168,7 @@ class MerchantInboundBillingServiceTest {
@Test
void shouldRequirePublishedFreightDetailAfterLoadingCompletes() {
InboundOrderEntity inbound = inbound("LOADED", "APPROVED", "CONFIRMED");
InboundOrderEntity inbound = inbound("LOADED", "APPROVED", "SENT");
when(orders.findByOrderId(10001L, 77L)).thenReturn(inbound);
when(feeDetails.publishedFreight(10001L, 88L))
.thenThrow(new BizException(com.baiyue.common.core.api.ResultCode.NOT_FOUND,