1
This commit is contained in:
@@ -0,0 +1,55 @@
|
||||
package com.baiyue.file.controller;
|
||||
|
||||
import com.baiyue.common.core.api.ResultCode;
|
||||
import com.baiyue.common.core.exception.BizException;
|
||||
import com.baiyue.common.security.AuthenticatedUser;
|
||||
import com.baiyue.file.service.ProductImageService;
|
||||
import jakarta.annotation.Resource;
|
||||
import org.springframework.http.CacheControl;
|
||||
import org.springframework.http.ContentDisposition;
|
||||
import org.springframework.http.HttpHeaders;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.security.access.prepost.PreAuthorize;
|
||||
import org.springframework.security.core.annotation.AuthenticationPrincipal;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.PathVariable;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
import java.nio.charset.StandardCharsets;
|
||||
|
||||
/** 鐢ㄤ簬骞冲彴绔鍗曡鎯呮煡鐪嬪晢鎴峰晢鍝佸浘鐗囥€? */
|
||||
@RestController
|
||||
@RequestMapping("/api/platform/v1/files/product-images")
|
||||
public class PlatformProductImageController {
|
||||
@Resource private ProductImageService images;
|
||||
|
||||
@GetMapping("/{tenantId}/{fileId}")
|
||||
@PreAuthorize("hasAuthority('platform:order:list')")
|
||||
public ResponseEntity<byte[]> download(
|
||||
@AuthenticationPrincipal AuthenticatedUser user,
|
||||
@PathVariable long tenantId,
|
||||
@PathVariable long fileId) {
|
||||
requirePlatform(user);
|
||||
if (tenantId <= 0 || fileId <= 0) {
|
||||
throw new BizException(ResultCode.BAD_REQUEST, "瀹㈡埛鍜屾枃浠禝D蹇呴』澶т簬0");
|
||||
}
|
||||
var image = images.download(tenantId, fileId);
|
||||
return ResponseEntity.ok()
|
||||
.cacheControl(CacheControl.noStore())
|
||||
.contentType(MediaType.parseMediaType(image.contentType()))
|
||||
.contentLength(image.content().length)
|
||||
.header(HttpHeaders.CONTENT_DISPOSITION, ContentDisposition.inline()
|
||||
.filename(image.fileName(), StandardCharsets.UTF_8).build().toString())
|
||||
.body(image.content());
|
||||
}
|
||||
|
||||
private static void requirePlatform(AuthenticatedUser user) {
|
||||
if (user == null || !"PLATFORM".equalsIgnoreCase(user.appCode())
|
||||
|| user.tenantId() == null || user.tenantId() != 0L
|
||||
|| user.userId() == null || user.userId() <= 0) {
|
||||
throw new BizException(ResultCode.FORBIDDEN, "闇€瑕佸钩鍙扮韬唤");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -77,6 +77,26 @@ class ProductImageControllerContractTest {
|
||||
assertThatThrownBy(() -> controller.upload(platform, file)).isInstanceOf(BizException.class);
|
||||
}
|
||||
|
||||
@Test
|
||||
void platformDownloadUsesTenantScopeAndOrderListPermission() throws Exception {
|
||||
RequestMapping mapping = PlatformProductImageController.class.getAnnotation(RequestMapping.class);
|
||||
assertThat(mapping.value()).contains("/api/platform/v1/files/product-images");
|
||||
var download = PlatformProductImageController.class.getDeclaredMethod(
|
||||
"download", AuthenticatedUser.class, long.class, long.class);
|
||||
assertThat(download.getAnnotation(PreAuthorize.class).value())
|
||||
.isEqualTo("hasAuthority('platform:order:list')");
|
||||
|
||||
ProductImageService service = mock(ProductImageService.class);
|
||||
PlatformProductImageController controller = new PlatformProductImageController();
|
||||
ReflectionTestUtils.setField(controller, "images", service);
|
||||
when(service.download(10001L, 31L)).thenReturn(
|
||||
new ProductImageService.Download("product.png", "image/png", new byte[] {1}));
|
||||
|
||||
var platform = new AuthenticatedUser(1L, 0L, 0L, 1L, "admin", "PLATFORM", "WEB", Set.of());
|
||||
assertThat(controller.download(platform, 10001L, 31L).getBody()).containsExactly(1);
|
||||
verify(service).download(10001L, 31L);
|
||||
}
|
||||
|
||||
private static AuthenticatedUser merchant(long tenantId) {
|
||||
return new AuthenticatedUser(2L, tenantId, tenantId, 2L, "merchant", "MERCHANT", "WEB", Set.of());
|
||||
}
|
||||
|
||||
+3
-1
@@ -68,7 +68,9 @@ public class ReconciliationStatementService {
|
||||
CustomerProfile customer = customer(request.customerId());
|
||||
long subjectId = activeSubject();
|
||||
List<Source> sources = eligibleSources(request);
|
||||
if (sources.isEmpty()) throw error("FIN_409", "没有符合结算条件的CNY应收费用来源");
|
||||
if (sources.isEmpty()) {
|
||||
throw error("FIN_409", "当前客户在所选账期内没有可生成的CNY应收费用,请调整账期或选择其他客户后重试");
|
||||
}
|
||||
BigDecimal total = sources.stream().map(Source::amount).reduce(BigDecimal.ZERO, BigDecimal::add);
|
||||
LocalDate dueDate = request.periodEnd().plusDays(customer.creditDays());
|
||||
String statementNo = documentNumbers.next("REC");
|
||||
|
||||
@@ -19,6 +19,7 @@ import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.util.ArrayList;
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.Comparator;
|
||||
@@ -181,10 +182,10 @@ public class UnifiedOrderQueryService {
|
||||
order.getChannelName(), order.getReceivingWarehouseId(), order.getReceivingWarehouseName(),
|
||||
order.getDestinationWarehouseId(), order.getDestinationWarehouseName(), null, null,
|
||||
order.getInboundCode(),
|
||||
order.getExpectedShipDate(), totalPackageCount(cargo), null, null, null,
|
||||
null, null, null, null, null, order.getPickupMethod(), order.getTaxMode(), order.getContainerMode(),
|
||||
order.getExpectedShipDate(), totalPackageCount(cargo), null, null, grossWeightKg(cargo), volumeCbm(cargo),
|
||||
null, null, null, null, order.getPickupMethod(), order.getTaxMode(), order.getContainerMode(),
|
||||
order.getCustomsInspection(), order.getDestinationType(), order.getAmazonWarehouseCode(),
|
||||
null, null, null, null, null, null, null, order.getExpressCompany(), order.getExpressTrackingNo(),
|
||||
null, null, null, null, netWeightKg(cargo), null, null, order.getExpressCompany(), order.getExpressTrackingNo(),
|
||||
string(order.getCreatedBy()), skuNos(cargo), totalQuantity(cargo), order.getShipmentId(), order.getReferenceId(),
|
||||
null, null, null, null, null,
|
||||
order.getCustomerRemark(), latestInternalNote,
|
||||
@@ -196,11 +197,13 @@ public class UnifiedOrderQueryService {
|
||||
order.getCustomerId(), order.getCustomerName(),
|
||||
order.getChannelName(), order.getReceivingWarehouseId(), order.getReceivingWarehouseName(),
|
||||
order.getDestinationWarehouseId(), order.getDestinationWarehouseName(), inbound.id(), inbound.version(), inbound.inboundCode(),
|
||||
order.getExpectedShipDate(), inbound.totalPackageCount(), null, inbound.locationCodes(),
|
||||
inbound.actualGrossWeightKg(), inbound.actualVolumeCbm(), inbound.expectedArrivalAt(), inbound.feeReviewStatus(),
|
||||
order.getExpectedShipDate(), inbound.totalPackageCount() != null ? inbound.totalPackageCount() : totalPackageCount(cargo), null, inbound.locationCodes(),
|
||||
inbound.actualGrossWeightKg() != null ? inbound.actualGrossWeightKg() : grossWeightKg(cargo),
|
||||
inbound.actualVolumeCbm() != null ? inbound.actualVolumeCbm() : volumeCbm(cargo), inbound.expectedArrivalAt(), inbound.feeReviewStatus(),
|
||||
inbound.companyName(), inbound.businessType(), order.getPickupMethod(), inbound.taxMode(), inbound.containerMode(),
|
||||
inbound.customsInspection(), inbound.destinationType(), inbound.destinationCode(), inbound.palletCount(),
|
||||
inbound.chargeableWeightKg(), inbound.chargeableVolumeCbm(), inbound.volumeWeightKg(), inbound.actualNetWeightKg(),
|
||||
inbound.chargeableWeightKg(), inbound.chargeableVolumeCbm(), inbound.volumeWeightKg(),
|
||||
inbound.actualNetWeightKg() != null ? inbound.actualNetWeightKg() : netWeightKg(cargo),
|
||||
inbound.measureCompletedAt(), inbound.inboundedAt(), inbound.expressCompanyName(), inbound.expressTrackingNo(),
|
||||
inbound.createdByName(), skuNos(cargo), totalQuantity(cargo), order.getShipmentId(), order.getReferenceId(), measurement(inbound),
|
||||
preload(summary.preload()), loading(summary.loading()),
|
||||
@@ -217,12 +220,16 @@ public class UnifiedOrderQueryService {
|
||||
parseOrderStatus(inbound.orderStatusSnapshot()),
|
||||
inbound.customerId(), inbound.customerName(), inbound.channelName(), inbound.warehouseId(),
|
||||
inbound.warehouseName(), inbound.deliveryWarehouseId(), inbound.deliveryWarehouseName(),
|
||||
inbound.id(), inbound.version(), inbound.inboundCode(), null, inbound.totalPackageCount(),
|
||||
null, inbound.locationCodes(), inbound.actualGrossWeightKg(),
|
||||
inbound.actualVolumeCbm(), inbound.expectedArrivalAt(), inbound.feeReviewStatus(), inbound.companyName(),
|
||||
inbound.id(), inbound.version(), inbound.inboundCode(), null,
|
||||
inbound.totalPackageCount() != null ? inbound.totalPackageCount() : totalPackageCount(cargo),
|
||||
null, inbound.locationCodes(),
|
||||
inbound.actualGrossWeightKg() != null ? inbound.actualGrossWeightKg() : grossWeightKg(cargo),
|
||||
inbound.actualVolumeCbm() != null ? inbound.actualVolumeCbm() : volumeCbm(cargo),
|
||||
inbound.expectedArrivalAt(), inbound.feeReviewStatus(), inbound.companyName(),
|
||||
inbound.businessType(), order == null ? null : order.getPickupMethod(), inbound.taxMode(), inbound.containerMode(),
|
||||
inbound.customsInspection(), inbound.destinationType(), inbound.destinationCode(), inbound.palletCount(),
|
||||
inbound.chargeableWeightKg(), inbound.chargeableVolumeCbm(), inbound.volumeWeightKg(), inbound.actualNetWeightKg(),
|
||||
inbound.chargeableWeightKg(), inbound.chargeableVolumeCbm(), inbound.volumeWeightKg(),
|
||||
inbound.actualNetWeightKg() != null ? inbound.actualNetWeightKg() : netWeightKg(cargo),
|
||||
inbound.measureCompletedAt(), inbound.inboundedAt(), inbound.expressCompanyName(), inbound.expressTrackingNo(),
|
||||
inbound.createdByName(), skuNos(cargo), totalQuantity(cargo), order == null ? null : order.getShipmentId(),
|
||||
order == null ? null : order.getReferenceId(), measurement(inbound), preload(summary.preload()), loading(summary.loading()),
|
||||
@@ -282,7 +289,20 @@ public class UnifiedOrderQueryService {
|
||||
return cargo == null ? null : cargo.totalPackageCount();
|
||||
}
|
||||
|
||||
private record CargoSummary(List<String> skuNos, Integer totalQuantity, Integer totalPackageCount) {
|
||||
private BigDecimal grossWeightKg(CargoSummary cargo) {
|
||||
return cargo == null ? null : cargo.grossWeightKg();
|
||||
}
|
||||
|
||||
private BigDecimal netWeightKg(CargoSummary cargo) {
|
||||
return cargo == null ? null : cargo.netWeightKg();
|
||||
}
|
||||
|
||||
private BigDecimal volumeCbm(CargoSummary cargo) {
|
||||
return cargo == null ? null : cargo.volumeCbm();
|
||||
}
|
||||
|
||||
private record CargoSummary(List<String> skuNos, Integer totalQuantity, Integer totalPackageCount,
|
||||
BigDecimal grossWeightKg, BigDecimal netWeightKg, BigDecimal volumeCbm) {
|
||||
private static CargoSummary from(List<OrderCargoEntity> cargoes) {
|
||||
List<String> skuNos = cargoes.stream().map(OrderCargoEntity::getSkuNo)
|
||||
.filter(Objects::nonNull).map(String::trim).filter(value -> !value.isEmpty()).distinct().toList();
|
||||
@@ -292,7 +312,16 @@ public class UnifiedOrderQueryService {
|
||||
.filter(Objects::nonNull).toList();
|
||||
Integer totalPackageCount = packageCounts.isEmpty() ? null
|
||||
: Math.toIntExact(packageCounts.stream().mapToLong(Integer::longValue).sum());
|
||||
return new CargoSummary(skuNos, totalQuantity, totalPackageCount);
|
||||
BigDecimal grossWeightKg = sum(cargoes, OrderCargoEntity::getGrossWeightKg);
|
||||
BigDecimal netWeightKg = sum(cargoes, OrderCargoEntity::getNetWeightKg);
|
||||
BigDecimal volumeCbm = sum(cargoes, OrderCargoEntity::getVolumeCbm);
|
||||
return new CargoSummary(skuNos, totalQuantity, totalPackageCount, grossWeightKg, netWeightKg, volumeCbm);
|
||||
}
|
||||
|
||||
private static BigDecimal sum(List<OrderCargoEntity> cargoes,
|
||||
Function<OrderCargoEntity, BigDecimal> value) {
|
||||
List<BigDecimal> values = cargoes.stream().map(value).filter(Objects::nonNull).toList();
|
||||
return values.isEmpty() ? null : values.stream().reduce(BigDecimal.ZERO, BigDecimal::add);
|
||||
}
|
||||
}
|
||||
private String inboundMainStatus(String status) {
|
||||
|
||||
@@ -84,13 +84,20 @@ class UnifiedOrderQueryServiceTest {
|
||||
OrderCargoEntity cargo = new OrderCargoEntity();
|
||||
cargo.setOrderId(77L);
|
||||
cargo.setPackageCount(100);
|
||||
cargo.setGrossWeightKg(new BigDecimal("12.5"));
|
||||
cargo.setNetWeightKg(new BigDecimal("11.2"));
|
||||
cargo.setVolumeCbm(new BigDecimal("0.375"));
|
||||
when(orders.unifiedPage(eq(10001L), eq(query), any()))
|
||||
.thenReturn(new PageResult<>(List.of(order), 1, 20, 1, 1));
|
||||
when(firstleg.summaries(eq("internal-token"), any())).thenReturn(ApiResponse.success(List.of()));
|
||||
when(orders.findCargoByOrderIds(10001L, List.of(77L))).thenReturn(List.of(cargo));
|
||||
|
||||
assertThat(service.page(10001L, query).records()).singleElement()
|
||||
.extracting(UnifiedOrderResponse.Row::totalPackageCount).isEqualTo(100);
|
||||
assertThat(service.page(10001L, query).records()).singleElement().satisfies(row -> {
|
||||
assertThat(row.totalPackageCount()).isEqualTo(100);
|
||||
assertThat(row.actualGrossWeightKg()).isEqualByComparingTo("12.5");
|
||||
assertThat(row.totalNetWeightKg()).isEqualByComparingTo("11.2");
|
||||
assertThat(row.actualVolumeCbm()).isEqualByComparingTo("0.375");
|
||||
});
|
||||
verify(orders).findCargoByOrderIds(10001L, List.of(77L));
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user