二期内容提交

This commit is contained in:
2026-08-04 19:48:35 +08:00
parent 954adb1287
commit c3bf4edd53
8 changed files with 281 additions and 6 deletions
@@ -32,4 +32,11 @@ class MerchantInboundBillingControllerContractTest {
"admin", "PLATFORM", "WEB", Set.of());
assertThatThrownBy(() -> controller.find(platform, 77L)).isInstanceOf(BizException.class);
}
@Test
void 商户测量图片复用订单查看权限() throws Exception {
var method = MerchantInboundBillingController.class.getDeclaredMethod(
"image", AuthenticatedUser.class, long.class, long.class);
assertThat(method.getAnnotation(PreAuthorize.class).value())
.isEqualTo("hasAuthority('merchant:order:view')");
}
}
@@ -3,10 +3,15 @@ package com.baiyue.firstleg.service;
import com.baiyue.common.core.exception.BizException;
import com.baiyue.firstleg.dto.FbaPricingDtos.FeeSnapshotResponse;
import com.baiyue.firstleg.dto.InboundOrderDetail;
import com.baiyue.firstleg.dto.InboundMeasurementResponses;
import com.baiyue.firstleg.client.MeasurementImageClient;
import com.baiyue.firstleg.entity.InboundOrderEntity;
import com.baiyue.firstleg.repository.InboundOrderRepository;
import org.junit.jupiter.api.Test;
import java.math.BigDecimal;
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;
@@ -17,20 +22,43 @@ import static org.mockito.Mockito.when;
class MerchantInboundBillingServiceTest {
private final InboundOrderRepository orders = mock(InboundOrderRepository.class);
private final FbaPricingService pricing = mock(FbaPricingService.class);
private final MerchantInboundBillingService service = new MerchantInboundBillingService(orders, pricing);
private final InboundMeasurementService measurements = mock(InboundMeasurementService.class);
private final MeasurementImageClient imageClient = mock(MeasurementImageClient.class);
private final MerchantInboundBillingService service = new MerchantInboundBillingService(
orders, pricing, measurements, imageClient, "internal-token");
@Test
void 客户只能看到本租户已完成入库且已发布的费用() {
InboundOrderEntity inbound = inbound("INBOUNDED", "SENT");
InboundOrderDetail detail = mock(InboundOrderDetail.class);
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),
new InboundOrderDetail.FileSummary(2L, "INTERNAL", "internal.pdf", "INTERNAL", 1, 1L, null)),
List.of(new InboundOrderDetail.InternalNoteSummary(1L, "内部备注", 1L, "客服", null)),
List.of(new InboundOrderDetail.StatusHistorySummary(null, "INBOUNDED", "COMPLETE",
"内部原因", 1L, "客服", null)));
InboundMeasurementResponses.Detail measurement = mock(InboundMeasurementResponses.Detail.class);
FeeSnapshotResponse fee = mock(FeeSnapshotResponse.class);
when(orders.findByOrderId(10001L, 77L)).thenReturn(inbound);
when(orders.detail(10001L, inbound)).thenReturn(detail);
when(measurements.detail(10001L, 88L)).thenReturn(measurement);
when(measurement.items()).thenReturn(List.of());
when(measurement.weightResults()).thenReturn(List.of());
when(pricing.latest(10001L, 88L)).thenReturn(fee);
when(fee.chargeMode()).thenReturn("KG");
when(fee.chargeUnit()).thenReturn("KG");
when(fee.actualWeightKg()).thenReturn(new BigDecimal("20"));
when(fee.actualVolumeCbm()).thenReturn(new BigDecimal("0.24"));
when(fee.convertedQuantity()).thenReturn(new BigDecimal("40.08"));
when(fee.chargeableQuantity()).thenReturn(new BigDecimal("40.08"));
var result = service.find(10001L, 77L);
assertThat(result.inbound()).isSameAs(detail);
assertThat(result.inbound().files()).extracting(InboundOrderDetail.FileSummary::fileId)
.containsExactly(1L);
assertThat(result.inbound().internalNotes()).isEmpty();
assertThat(result.inbound().statusHistory()).isEmpty();
assertThat(result.billingBasis().chargeableBasis()).isEqualTo("VOLUME_WEIGHT");
assertThat(result.latestFee()).isSameAs(fee);
verify(orders).findByOrderId(10001L, 77L);
}
@@ -56,6 +84,42 @@ class MerchantInboundBillingServiceTest {
verify(pricing, never()).latest(20002L, 88L);
}
@Test
void 只能下载已发布计费明细实际引用的图片() {
InboundOrderEntity inbound = inbound("INBOUNDED", "SENT");
InboundMeasurementResponses.Detail measurement = mock(InboundMeasurementResponses.Detail.class);
InboundMeasurementResponses.Item item = mock(InboundMeasurementResponses.Item.class);
when(item.intelligentImageFileId()).thenReturn(41L);
when(measurement.items()).thenReturn(List.of(item));
when(measurement.weightResults()).thenReturn(List.of());
when(orders.findByOrderId(10001L, 77L)).thenReturn(inbound);
when(measurements.detail(10001L, 88L)).thenReturn(measurement);
when(imageClient.download("internal-token", 10001L, 88L, 41L)).thenReturn(
org.springframework.http.ResponseEntity.ok()
.contentType(org.springframework.http.MediaType.IMAGE_PNG)
.body(new byte[]{1, 2, 3}));
var image = service.downloadImage(10001L, 77L, 41L);
assertThat(image.contentType()).isEqualTo("image/png");
assertThat(image.content()).containsExactly(1, 2, 3);
}
@Test
void 拒绝下载未被当前计费明细引用的图片() {
InboundOrderEntity inbound = inbound("INBOUNDED", "SENT");
InboundMeasurementResponses.Detail measurement = mock(InboundMeasurementResponses.Detail.class);
when(measurement.items()).thenReturn(List.of());
when(measurement.weightResults()).thenReturn(List.of());
when(orders.findByOrderId(10001L, 77L)).thenReturn(inbound);
when(measurements.detail(10001L, 88L)).thenReturn(measurement);
assertThatThrownBy(() -> service.downloadImage(10001L, 77L, 99L))
.isInstanceOf(BizException.class)
.hasMessageContaining("不存在该测量图片");
verify(imageClient, never()).download("internal-token", 10001L, 88L, 99L);
}
private static InboundOrderEntity inbound(String process, String feeStatus) {
InboundOrderEntity inbound = new InboundOrderEntity();
inbound.setId(88L);