Merge branch 'test' of http://8.163.30.128:10082/java-project/baiyue-firstleg into test
This commit is contained in:
+19
@@ -4,6 +4,7 @@ import com.baiyue.common.core.api.ApiResponse;
|
|||||||
import com.baiyue.common.core.api.ResultCode;
|
import com.baiyue.common.core.api.ResultCode;
|
||||||
import com.baiyue.common.core.exception.BizException;
|
import com.baiyue.common.core.exception.BizException;
|
||||||
import com.baiyue.firstleg.dto.OrderApprovedInboundCommand;
|
import com.baiyue.firstleg.dto.OrderApprovedInboundCommand;
|
||||||
|
import com.baiyue.firstleg.dto.InboundOrderReference;
|
||||||
import com.baiyue.firstleg.service.InboundOrderCreationService;
|
import com.baiyue.firstleg.service.InboundOrderCreationService;
|
||||||
import org.springframework.beans.factory.annotation.Value;
|
import org.springframework.beans.factory.annotation.Value;
|
||||||
import org.springframework.web.bind.annotation.PostMapping;
|
import org.springframework.web.bind.annotation.PostMapping;
|
||||||
@@ -11,6 +12,9 @@ import org.springframework.web.bind.annotation.RequestBody;
|
|||||||
import org.springframework.web.bind.annotation.RequestHeader;
|
import org.springframework.web.bind.annotation.RequestHeader;
|
||||||
import org.springframework.web.bind.annotation.RequestMapping;
|
import org.springframework.web.bind.annotation.RequestMapping;
|
||||||
import org.springframework.web.bind.annotation.RestController;
|
import org.springframework.web.bind.annotation.RestController;
|
||||||
|
import jakarta.validation.Valid;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
import java.nio.charset.StandardCharsets;
|
import java.nio.charset.StandardCharsets;
|
||||||
import java.security.MessageDigest;
|
import java.security.MessageDigest;
|
||||||
@@ -41,4 +45,19 @@ public class InternalInboundOrderController {
|
|||||||
}
|
}
|
||||||
return ApiResponse.success(service.createFromApprovedOrder(command));
|
return ApiResponse.success(service.createFromApprovedOrder(command));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@PostMapping("/order-references")
|
||||||
|
public ApiResponse<List<InboundOrderReference.Item>> references(
|
||||||
|
@RequestHeader(value = "X-Internal-Service-Token", required = false) String token,
|
||||||
|
@Valid @RequestBody InboundOrderReference.BatchRequest request) {
|
||||||
|
requireToken(token);
|
||||||
|
return ApiResponse.success(service.findReferences(
|
||||||
|
request.tenantId(), request.orderIds().stream().distinct().toList()));
|
||||||
|
}
|
||||||
|
|
||||||
|
private void requireToken(String token) {
|
||||||
|
if (token == null || !MessageDigest.isEqual(expectedToken, token.getBytes(StandardCharsets.UTF_8))) {
|
||||||
|
throw new BizException(ResultCode.FORBIDDEN, "内部服务凭证无效");
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,20 @@
|
|||||||
|
package com.baiyue.firstleg.dto;
|
||||||
|
|
||||||
|
import jakarta.validation.constraints.NotEmpty;
|
||||||
|
import jakarta.validation.constraints.Positive;
|
||||||
|
import jakarta.validation.constraints.Size;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/** 订单服务批量读取头程入库引用的内部契约。 */
|
||||||
|
public final class InboundOrderReference {
|
||||||
|
private InboundOrderReference() {
|
||||||
|
}
|
||||||
|
|
||||||
|
public record BatchRequest(@Positive long tenantId,
|
||||||
|
@NotEmpty @Size(max = 200) List<@Positive Long> orderIds) {
|
||||||
|
}
|
||||||
|
|
||||||
|
public record Item(Long orderId, Long inboundId, String inboundCode, String processStatus) {
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -2,6 +2,7 @@ package com.baiyue.firstleg.service;
|
|||||||
|
|
||||||
import com.baomidou.mybatisplus.core.toolkit.IdWorker;
|
import com.baomidou.mybatisplus.core.toolkit.IdWorker;
|
||||||
import com.baiyue.firstleg.dto.OrderApprovedInboundCommand;
|
import com.baiyue.firstleg.dto.OrderApprovedInboundCommand;
|
||||||
|
import com.baiyue.firstleg.dto.InboundOrderReference;
|
||||||
import com.baiyue.firstleg.entity.InboundOrderEntity;
|
import com.baiyue.firstleg.entity.InboundOrderEntity;
|
||||||
import com.baiyue.firstleg.entity.InboundStatusHistoryEntity;
|
import com.baiyue.firstleg.entity.InboundStatusHistoryEntity;
|
||||||
import com.baiyue.firstleg.mapper.InboundOrderMapper;
|
import com.baiyue.firstleg.mapper.InboundOrderMapper;
|
||||||
@@ -10,6 +11,7 @@ import org.springframework.stereotype.Service;
|
|||||||
import org.springframework.transaction.annotation.Transactional;
|
import org.springframework.transaction.annotation.Transactional;
|
||||||
|
|
||||||
import java.time.LocalDateTime;
|
import java.time.LocalDateTime;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
/** 将已审核的订单快照幂等转换为待测量入库单。 */
|
/** 将已审核的订单快照幂等转换为待测量入库单。 */
|
||||||
@Service
|
@Service
|
||||||
@@ -86,4 +88,16 @@ public class InboundOrderCreationService {
|
|||||||
histories.insert(history);
|
histories.insert(history);
|
||||||
return inbound.getId();
|
return inbound.getId();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public List<InboundOrderReference.Item> findReferences(long tenantId, List<Long> orderIds) {
|
||||||
|
if (orderIds.isEmpty()) return List.of();
|
||||||
|
return orders.selectList(new com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper<InboundOrderEntity>()
|
||||||
|
.eq(InboundOrderEntity::getTenantId, tenantId)
|
||||||
|
.in(InboundOrderEntity::getOrderId, orderIds)
|
||||||
|
.orderByDesc(InboundOrderEntity::getCreatedAt))
|
||||||
|
.stream()
|
||||||
|
.map(inbound -> new InboundOrderReference.Item(
|
||||||
|
inbound.getOrderId(), inbound.getId(), inbound.getInboundCode(), inbound.getProcessStatus()))
|
||||||
|
.toList();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+40
@@ -0,0 +1,40 @@
|
|||||||
|
package com.baiyue.firstleg.controller;
|
||||||
|
|
||||||
|
import com.baiyue.common.core.exception.BizException;
|
||||||
|
import com.baiyue.firstleg.dto.InboundOrderReference;
|
||||||
|
import com.baiyue.firstleg.service.InboundOrderCreationService;
|
||||||
|
import org.junit.jupiter.api.Test;
|
||||||
|
|
||||||
|
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;
|
||||||
|
import static org.mockito.Mockito.verify;
|
||||||
|
import static org.mockito.Mockito.when;
|
||||||
|
|
||||||
|
class InternalInboundOrderReferenceControllerTest {
|
||||||
|
private final InboundOrderCreationService service = mock(InboundOrderCreationService.class);
|
||||||
|
private final InternalInboundOrderController controller =
|
||||||
|
new InternalInboundOrderController(service, "internal-token");
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void 使用内部令牌按租户批量查询订单入仓编码() {
|
||||||
|
var request = new InboundOrderReference.BatchRequest(10001L, List.of(77L, 77L, 78L));
|
||||||
|
when(service.findReferences(10001L, List.of(77L, 78L))).thenReturn(List.of(
|
||||||
|
new InboundOrderReference.Item(77L, 88L, "RK-77", "WAIT_MEASURE")));
|
||||||
|
|
||||||
|
var response = controller.references("internal-token", request);
|
||||||
|
|
||||||
|
assertThat(response.data()).extracting(InboundOrderReference.Item::inboundCode)
|
||||||
|
.containsExactly("RK-77");
|
||||||
|
verify(service).findReferences(10001L, List.of(77L, 78L));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void 错误内部令牌不能查询任意租户的入仓编码() {
|
||||||
|
var request = new InboundOrderReference.BatchRequest(10001L, List.of(77L));
|
||||||
|
assertThatThrownBy(() -> controller.references("bad-token", request))
|
||||||
|
.isInstanceOf(BizException.class);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -7,6 +7,7 @@ import org.springframework.web.bind.annotation.RequestBody;
|
|||||||
import org.springframework.web.bind.annotation.RequestHeader;
|
import org.springframework.web.bind.annotation.RequestHeader;
|
||||||
|
|
||||||
import java.time.LocalDateTime;
|
import java.time.LocalDateTime;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
/** 订单审核事件投递到头程入库域的内部客户端。 */
|
/** 订单审核事件投递到头程入库域的内部客户端。 */
|
||||||
@FeignClient(name = "firstleg-service", contextId = "orderFirstlegInboundClient",
|
@FeignClient(name = "firstleg-service", contextId = "orderFirstlegInboundClient",
|
||||||
@@ -16,6 +17,17 @@ public interface FirstlegInboundClient {
|
|||||||
ApiResponse<Long> create(@RequestHeader("X-Internal-Service-Token") String token,
|
ApiResponse<Long> create(@RequestHeader("X-Internal-Service-Token") String token,
|
||||||
@RequestBody OrderApprovedInboundCommand command);
|
@RequestBody OrderApprovedInboundCommand command);
|
||||||
|
|
||||||
|
@PostMapping("/order-references")
|
||||||
|
ApiResponse<List<InboundReference>> references(
|
||||||
|
@RequestHeader("X-Internal-Service-Token") String token,
|
||||||
|
@RequestBody InboundReferenceRequest request);
|
||||||
|
|
||||||
|
record InboundReferenceRequest(long tenantId, List<Long> orderIds) {
|
||||||
|
}
|
||||||
|
|
||||||
|
record InboundReference(Long orderId, Long inboundId, String inboundCode, String processStatus) {
|
||||||
|
}
|
||||||
|
|
||||||
record OrderApprovedInboundCommand(
|
record OrderApprovedInboundCommand(
|
||||||
long tenantId, long orderId, String orderNo, Long customerId, String customerName,
|
long tenantId, long orderId, String orderNo, Long customerId, String customerName,
|
||||||
Long warehouseId, String warehouseName, Long deliveryWarehouseId, String deliveryWarehouseName,
|
Long warehouseId, String warehouseName, Long deliveryWarehouseId, String deliveryWarehouseName,
|
||||||
|
|||||||
+9
-4
@@ -6,10 +6,12 @@ import com.baiyue.common.core.api.PageResult;
|
|||||||
import com.baiyue.common.security.AuthenticatedUser;
|
import com.baiyue.common.security.AuthenticatedUser;
|
||||||
import com.baiyue.order.dto.OrderDetailResponse;
|
import com.baiyue.order.dto.OrderDetailResponse;
|
||||||
import com.baiyue.order.dto.OrderRequests;
|
import com.baiyue.order.dto.OrderRequests;
|
||||||
import com.baiyue.order.entity.OrderEntity;
|
import com.baiyue.order.dto.MerchantInboundOrderQuery;
|
||||||
|
import com.baiyue.order.dto.MerchantInboundOrderRow;
|
||||||
import com.baiyue.order.entity.OrderStatus;
|
import com.baiyue.order.entity.OrderStatus;
|
||||||
import com.baiyue.order.service.OrderApplicationService;
|
import com.baiyue.order.service.OrderApplicationService;
|
||||||
import com.baiyue.order.service.OrderScopeGuard;
|
import com.baiyue.order.service.OrderScopeGuard;
|
||||||
|
import com.baiyue.order.service.MerchantInboundOrderListService;
|
||||||
import io.swagger.v3.oas.annotations.Operation;
|
import io.swagger.v3.oas.annotations.Operation;
|
||||||
import io.swagger.v3.oas.annotations.Parameter;
|
import io.swagger.v3.oas.annotations.Parameter;
|
||||||
import io.swagger.v3.oas.annotations.responses.ApiResponses;
|
import io.swagger.v3.oas.annotations.responses.ApiResponses;
|
||||||
@@ -39,6 +41,8 @@ import org.springframework.web.bind.annotation.RestController;
|
|||||||
public class MerchantFirstLegOrderController {
|
public class MerchantFirstLegOrderController {
|
||||||
@Resource
|
@Resource
|
||||||
private OrderApplicationService service;
|
private OrderApplicationService service;
|
||||||
|
@Resource
|
||||||
|
private MerchantInboundOrderListService inboundOrderListService;
|
||||||
|
|
||||||
@BusinessAudit(event = "ORDER_CREATE", resourceType = "FIRST_LEG_ORDER", description = "Create draft / 新建草稿")
|
@BusinessAudit(event = "ORDER_CREATE", resourceType = "FIRST_LEG_ORDER", description = "Create draft / 新建草稿")
|
||||||
@Operation(summary = "Create draft / 新建草稿", description = "Creates a first-leg draft order in the authenticated merchant tenant. / 在当前认证商户租户下创建头程订单草稿。")
|
@Operation(summary = "Create draft / 新建草稿", description = "Creates a first-leg draft order in the authenticated merchant tenant. / 在当前认证商户租户下创建头程订单草稿。")
|
||||||
@@ -80,9 +84,10 @@ public class MerchantFirstLegOrderController {
|
|||||||
})
|
})
|
||||||
@GetMapping
|
@GetMapping
|
||||||
@PreAuthorize("hasAuthority('merchant:order:list')")
|
@PreAuthorize("hasAuthority('merchant:order:list')")
|
||||||
public ApiResponse<PageResult<OrderEntity>> page(@AuthenticationPrincipal AuthenticatedUser user,
|
public ApiResponse<PageResult<MerchantInboundOrderRow>> page(
|
||||||
@Valid OrderRequests.QueryRequest query) {
|
@AuthenticationPrincipal AuthenticatedUser user,
|
||||||
return ApiResponse.success(service.page(OrderScopeGuard.merchant(user), query));
|
@Valid MerchantInboundOrderQuery query) {
|
||||||
|
return ApiResponse.success(inboundOrderListService.page(OrderScopeGuard.merchant(user), query));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Operation(summary = "My order detail / 我的订单详情", description = "Returns the order aggregate only when it belongs to the authenticated merchant tenant. / 仅当订单属于当前认证商户租户时返回订单聚合详情。")
|
@Operation(summary = "My order detail / 我的订单详情", description = "Returns the order aggregate only when it belongs to the authenticated merchant tenant. / 仅当订单属于当前认证商户租户时返回订单聚合详情。")
|
||||||
|
|||||||
@@ -0,0 +1,31 @@
|
|||||||
|
package com.baiyue.order.dto;
|
||||||
|
|
||||||
|
import com.baiyue.order.entity.OrderStatus;
|
||||||
|
import jakarta.validation.constraints.Max;
|
||||||
|
import jakarta.validation.constraints.Min;
|
||||||
|
import jakarta.validation.constraints.Size;
|
||||||
|
|
||||||
|
import java.time.LocalDateTime;
|
||||||
|
|
||||||
|
/** 客户端入库订单列表查询条件。 */
|
||||||
|
public record MerchantInboundOrderQuery(
|
||||||
|
@Size(max = 64) String keyword,
|
||||||
|
@Size(max = 64) String orderNo,
|
||||||
|
Long receivingWarehouseId,
|
||||||
|
@Size(max = 128) String channelName,
|
||||||
|
@Size(max = 128) String customerContact,
|
||||||
|
Long customerId,
|
||||||
|
OrderStatus status,
|
||||||
|
OrderStatus operationStatus,
|
||||||
|
@Size(max = 32) String destinationType,
|
||||||
|
Long destinationWarehouseId,
|
||||||
|
LocalDateTime createdFrom,
|
||||||
|
LocalDateTime createdTo,
|
||||||
|
@Min(1) long page,
|
||||||
|
@Min(1) @Max(200) long size
|
||||||
|
) {
|
||||||
|
public MerchantInboundOrderQuery {
|
||||||
|
if (page == 0) page = 1;
|
||||||
|
if (size == 0) size = 20;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,47 @@
|
|||||||
|
package com.baiyue.order.dto;
|
||||||
|
|
||||||
|
import com.baiyue.order.entity.OrderStatus;
|
||||||
|
|
||||||
|
import java.math.BigDecimal;
|
||||||
|
import java.time.LocalDateTime;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/** 客户端入库订单列表行,聚合订单、货物、收货方和头程入库编码。 */
|
||||||
|
public record MerchantInboundOrderRow(
|
||||||
|
Long orderId,
|
||||||
|
String orderNo,
|
||||||
|
Integer packageCount,
|
||||||
|
BigDecimal weightKg,
|
||||||
|
String inboundCode,
|
||||||
|
String channelName,
|
||||||
|
String destinationType,
|
||||||
|
String customerName,
|
||||||
|
String receivingCompanyName,
|
||||||
|
String specificationModel,
|
||||||
|
OrderStatus status,
|
||||||
|
Integer totalQuantity,
|
||||||
|
BigDecimal totalGrossWeightKg,
|
||||||
|
BigDecimal totalNetWeightKg,
|
||||||
|
BigDecimal totalVolumeCbm,
|
||||||
|
BigDecimal customsDeclaredUnitPrice,
|
||||||
|
BigDecimal customsDeclaredAmount,
|
||||||
|
String currency,
|
||||||
|
String material,
|
||||||
|
String productUsage,
|
||||||
|
String brand,
|
||||||
|
LocalDateTime createdAt,
|
||||||
|
String trackingNo,
|
||||||
|
String internationalOrderNo,
|
||||||
|
String referenceId,
|
||||||
|
Long operatorId,
|
||||||
|
String operatorName,
|
||||||
|
String remark,
|
||||||
|
List<CargoColumn> cargoes
|
||||||
|
) {
|
||||||
|
public record CargoColumn(
|
||||||
|
Long cargoId, Integer itemNo, String cargoName, Integer packageCount,
|
||||||
|
Integer totalQuantity, BigDecimal grossWeightKg, BigDecimal netWeightKg,
|
||||||
|
BigDecimal volumeCbm, BigDecimal unitDeclaredValue, BigDecimal declaredValue,
|
||||||
|
String currency, String model, String material, String productUsage, String brand) {
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -2,6 +2,7 @@ package com.baiyue.order.repository;
|
|||||||
|
|
||||||
import com.baiyue.common.core.api.PageResult;
|
import com.baiyue.common.core.api.PageResult;
|
||||||
import com.baiyue.order.dto.OrderRequests;
|
import com.baiyue.order.dto.OrderRequests;
|
||||||
|
import com.baiyue.order.dto.MerchantInboundOrderQuery;
|
||||||
import com.baiyue.order.entity.*;
|
import com.baiyue.order.entity.*;
|
||||||
import com.baiyue.order.mapper.*;
|
import com.baiyue.order.mapper.*;
|
||||||
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||||
@@ -113,6 +114,62 @@ public class OrderRepository {
|
|||||||
return PageResult.from(orderMapper.selectPage(new Page<>(query.page(), query.size()), wrapper));
|
return PageResult.from(orderMapper.selectPage(new Page<>(query.page(), query.size()), wrapper));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public PageResult<OrderEntity> merchantInboundPage(long tenantId, MerchantInboundOrderQuery query) {
|
||||||
|
com.baiyue.order.entity.OrderStatus effectiveStatus = query.operationStatus() == null
|
||||||
|
? query.status() : query.operationStatus();
|
||||||
|
LambdaQueryWrapper<OrderEntity> wrapper = new LambdaQueryWrapper<OrderEntity>()
|
||||||
|
.eq(OrderEntity::getTenantId, tenantId)
|
||||||
|
.like(StringUtils.hasText(query.orderNo()), OrderEntity::getOrderNo, query.orderNo())
|
||||||
|
.eq(query.receivingWarehouseId() != null, OrderEntity::getReceivingWarehouseId,
|
||||||
|
query.receivingWarehouseId())
|
||||||
|
.eq(StringUtils.hasText(query.channelName()), OrderEntity::getChannelName, query.channelName())
|
||||||
|
.eq(query.customerId() != null, OrderEntity::getCustomerId, query.customerId())
|
||||||
|
.eq(effectiveStatus != null, OrderEntity::getStatus, effectiveStatus)
|
||||||
|
.eq(StringUtils.hasText(query.destinationType()), OrderEntity::getDestinationType,
|
||||||
|
query.destinationType())
|
||||||
|
.eq(query.destinationWarehouseId() != null, OrderEntity::getDestinationWarehouseId,
|
||||||
|
query.destinationWarehouseId())
|
||||||
|
.ge(query.createdFrom() != null, OrderEntity::getCreatedAt, query.createdFrom())
|
||||||
|
.le(query.createdTo() != null, OrderEntity::getCreatedAt, query.createdTo())
|
||||||
|
.and(StringUtils.hasText(query.keyword()), nested -> nested
|
||||||
|
.like(OrderEntity::getOrderNo, query.keyword())
|
||||||
|
.or().like(OrderEntity::getCustomerName, query.keyword()))
|
||||||
|
.and(StringUtils.hasText(query.customerContact()), nested -> nested
|
||||||
|
.like(OrderEntity::getCustomerName, query.customerContact())
|
||||||
|
.or().apply("EXISTS (SELECT 1 FROM ord_order_party p "
|
||||||
|
+ "WHERE p.tenant_id = {0} AND p.order_id = ord_order.id AND p.deleted = 0 "
|
||||||
|
+ "AND (p.contact_name LIKE CONCAT('%', {1}, '%') "
|
||||||
|
+ "OR p.phone LIKE CONCAT('%', {1}, '%')))",
|
||||||
|
tenantId, query.customerContact()))
|
||||||
|
.orderByDesc(OrderEntity::getCreatedAt)
|
||||||
|
.orderByDesc(OrderEntity::getId);
|
||||||
|
return PageResult.from(orderMapper.selectPage(new Page<>(query.page(), query.size()), wrapper));
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<OrderCargoEntity> findCargoByOrderIds(long tenantId, List<Long> orderIds) {
|
||||||
|
if (orderIds.isEmpty()) return List.of();
|
||||||
|
return cargoMapper.selectList(new LambdaQueryWrapper<OrderCargoEntity>()
|
||||||
|
.eq(OrderCargoEntity::getTenantId, tenantId)
|
||||||
|
.in(OrderCargoEntity::getOrderId, orderIds)
|
||||||
|
.orderByAsc(OrderCargoEntity::getOrderId)
|
||||||
|
.orderByAsc(OrderCargoEntity::getItemNo));
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<OrderPartyEntity> findPartiesByOrderIds(long tenantId, List<Long> orderIds) {
|
||||||
|
if (orderIds.isEmpty()) return List.of();
|
||||||
|
return partyMapper.selectList(new LambdaQueryWrapper<OrderPartyEntity>()
|
||||||
|
.eq(OrderPartyEntity::getTenantId, tenantId)
|
||||||
|
.in(OrderPartyEntity::getOrderId, orderIds));
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<OrderStatusHistoryEntity> findHistoryByOrderIds(long tenantId, List<Long> orderIds) {
|
||||||
|
if (orderIds.isEmpty()) return List.of();
|
||||||
|
return historyMapper.selectList(new LambdaQueryWrapper<OrderStatusHistoryEntity>()
|
||||||
|
.eq(OrderStatusHistoryEntity::getTenantId, tenantId)
|
||||||
|
.in(OrderStatusHistoryEntity::getOrderId, orderIds)
|
||||||
|
.orderByDesc(OrderStatusHistoryEntity::getOccurredAt));
|
||||||
|
}
|
||||||
|
|
||||||
public Map<Long, Long> countByTenantIds(List<Long> tenantIds) {
|
public Map<Long, Long> countByTenantIds(List<Long> tenantIds) {
|
||||||
if (tenantIds.isEmpty()) return Map.of();
|
if (tenantIds.isEmpty()) return Map.of();
|
||||||
var rows = orderMapper.selectMaps(new QueryWrapper<OrderEntity>()
|
var rows = orderMapper.selectMaps(new QueryWrapper<OrderEntity>()
|
||||||
|
|||||||
@@ -0,0 +1,136 @@
|
|||||||
|
package com.baiyue.order.service;
|
||||||
|
|
||||||
|
import com.baiyue.common.core.api.PageResult;
|
||||||
|
import com.baiyue.common.core.api.ResultCode;
|
||||||
|
import com.baiyue.common.core.exception.BizException;
|
||||||
|
import com.baiyue.order.client.FirstlegInboundClient;
|
||||||
|
import com.baiyue.order.dto.MerchantInboundOrderQuery;
|
||||||
|
import com.baiyue.order.dto.MerchantInboundOrderRow;
|
||||||
|
import com.baiyue.order.entity.OrderCargoEntity;
|
||||||
|
import com.baiyue.order.entity.OrderEntity;
|
||||||
|
import com.baiyue.order.entity.OrderPartyEntity;
|
||||||
|
import com.baiyue.order.entity.OrderStatusHistoryEntity;
|
||||||
|
import com.baiyue.order.repository.OrderRepository;
|
||||||
|
import feign.FeignException;
|
||||||
|
import org.springframework.beans.factory.annotation.Value;
|
||||||
|
import org.springframework.stereotype.Service;
|
||||||
|
|
||||||
|
import java.math.BigDecimal;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.Objects;
|
||||||
|
import java.util.function.Function;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
|
@Service
|
||||||
|
public class MerchantInboundOrderListService {
|
||||||
|
private final OrderRepository repository;
|
||||||
|
private final FirstlegInboundClient firstleg;
|
||||||
|
private final String internalToken;
|
||||||
|
|
||||||
|
public MerchantInboundOrderListService(
|
||||||
|
OrderRepository repository,
|
||||||
|
FirstlegInboundClient firstleg,
|
||||||
|
@Value("${baiyue.security.internal-service-token}") String internalToken) {
|
||||||
|
this.repository = repository;
|
||||||
|
this.firstleg = firstleg;
|
||||||
|
this.internalToken = internalToken;
|
||||||
|
}
|
||||||
|
|
||||||
|
public PageResult<MerchantInboundOrderRow> page(long tenantId, MerchantInboundOrderQuery query) {
|
||||||
|
PageResult<OrderEntity> source = repository.merchantInboundPage(tenantId, query);
|
||||||
|
List<Long> orderIds = source.records().stream().map(OrderEntity::getId).toList();
|
||||||
|
if (orderIds.isEmpty()) {
|
||||||
|
return new PageResult<>(List.of(), source.page(), source.size(), source.total(), source.pages());
|
||||||
|
}
|
||||||
|
|
||||||
|
Map<Long, List<OrderCargoEntity>> cargoes = repository.findCargoByOrderIds(tenantId, orderIds)
|
||||||
|
.stream().collect(Collectors.groupingBy(OrderCargoEntity::getOrderId));
|
||||||
|
Map<Long, OrderPartyEntity> consignees = repository.findPartiesByOrderIds(tenantId, orderIds)
|
||||||
|
.stream().filter(party -> "RECEIVER".equals(party.getPartyType()))
|
||||||
|
.collect(Collectors.toMap(OrderPartyEntity::getOrderId, Function.identity(), (left, right) -> left));
|
||||||
|
Map<Long, OrderStatusHistoryEntity> latestHistory = repository.findHistoryByOrderIds(tenantId, orderIds)
|
||||||
|
.stream().collect(Collectors.toMap(
|
||||||
|
OrderStatusHistoryEntity::getOrderId, Function.identity(), (latest, ignored) -> latest));
|
||||||
|
Map<Long, FirstlegInboundClient.InboundReference> inboundReferences = references(tenantId, orderIds);
|
||||||
|
|
||||||
|
List<MerchantInboundOrderRow> records = source.records().stream()
|
||||||
|
.map(order -> row(order, cargoes.getOrDefault(order.getId(), List.of()),
|
||||||
|
consignees.get(order.getId()), latestHistory.get(order.getId()),
|
||||||
|
inboundReferences.get(order.getId())))
|
||||||
|
.toList();
|
||||||
|
return new PageResult<>(records, source.page(), source.size(), source.total(), source.pages());
|
||||||
|
}
|
||||||
|
|
||||||
|
private Map<Long, FirstlegInboundClient.InboundReference> references(long tenantId, List<Long> orderIds) {
|
||||||
|
try {
|
||||||
|
var response = firstleg.references(internalToken,
|
||||||
|
new FirstlegInboundClient.InboundReferenceRequest(tenantId, orderIds));
|
||||||
|
if (response == null || !response.successful() || response.data() == null) {
|
||||||
|
throw new BizException(ResultCode.SERVICE_UNAVAILABLE, "头程入库引用查询响应无效");
|
||||||
|
}
|
||||||
|
return response.data().stream().collect(Collectors.toMap(
|
||||||
|
FirstlegInboundClient.InboundReference::orderId, Function.identity(), (left, right) -> left));
|
||||||
|
} catch (FeignException exception) {
|
||||||
|
throw new BizException(ResultCode.SERVICE_UNAVAILABLE, "头程服务暂时不可用");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private MerchantInboundOrderRow row(
|
||||||
|
OrderEntity order,
|
||||||
|
List<OrderCargoEntity> cargoes,
|
||||||
|
OrderPartyEntity consignee,
|
||||||
|
OrderStatusHistoryEntity latestHistory,
|
||||||
|
FirstlegInboundClient.InboundReference inbound) {
|
||||||
|
int packageCount = cargoes.stream().map(OrderCargoEntity::getPackageCount)
|
||||||
|
.filter(Objects::nonNull).mapToInt(Integer::intValue).sum();
|
||||||
|
int totalQuantity = cargoes.stream().map(OrderCargoEntity::getTotalQuantity)
|
||||||
|
.filter(Objects::nonNull).mapToInt(Integer::intValue).sum();
|
||||||
|
BigDecimal grossWeight = sum(cargoes, OrderCargoEntity::getGrossWeightKg);
|
||||||
|
BigDecimal netWeight = sum(cargoes, OrderCargoEntity::getNetWeightKg);
|
||||||
|
BigDecimal volume = sum(cargoes, OrderCargoEntity::getVolumeCbm);
|
||||||
|
BigDecimal declaredAmount = sum(cargoes, OrderCargoEntity::getDeclaredValue);
|
||||||
|
|
||||||
|
List<MerchantInboundOrderRow.CargoColumn> cargoColumns = cargoes.stream()
|
||||||
|
.map(cargo -> new MerchantInboundOrderRow.CargoColumn(
|
||||||
|
cargo.getId(), cargo.getItemNo(), cargo.getCargoName(), cargo.getPackageCount(),
|
||||||
|
cargo.getTotalQuantity(), cargo.getGrossWeightKg(), cargo.getNetWeightKg(),
|
||||||
|
cargo.getVolumeCbm(), cargo.getUnitDeclaredValue(), cargo.getDeclaredValue(),
|
||||||
|
cargo.getCurrency(), cargo.getModel(), cargo.getMaterial(), cargo.getProductUsage(),
|
||||||
|
cargo.getBrand()))
|
||||||
|
.toList();
|
||||||
|
|
||||||
|
return new MerchantInboundOrderRow(
|
||||||
|
order.getId(), order.getOrderNo(), packageCount, grossWeight,
|
||||||
|
inbound == null ? null : inbound.inboundCode(), order.getChannelName(),
|
||||||
|
order.getDestinationType(), order.getCustomerName(),
|
||||||
|
consignee == null ? null : consignee.getCompanyName(), joined(cargoes, OrderCargoEntity::getModel),
|
||||||
|
order.getStatus(), totalQuantity, grossWeight, netWeight, volume,
|
||||||
|
commonUnitPrice(cargoes), declaredAmount, joined(cargoes, OrderCargoEntity::getCurrency),
|
||||||
|
joined(cargoes, OrderCargoEntity::getMaterial),
|
||||||
|
joined(cargoes, OrderCargoEntity::getProductUsage),
|
||||||
|
joined(cargoes, OrderCargoEntity::getBrand), order.getCreatedAt(),
|
||||||
|
order.getExpressTrackingNo(), order.getShipmentId(), order.getReferenceId(),
|
||||||
|
latestHistory == null ? order.getCreatedBy() : latestHistory.getOperatorId(),
|
||||||
|
latestHistory == null ? null : latestHistory.getOperatorName(), order.getCustomerRemark(),
|
||||||
|
cargoColumns);
|
||||||
|
}
|
||||||
|
|
||||||
|
private BigDecimal sum(List<OrderCargoEntity> cargoes,
|
||||||
|
Function<OrderCargoEntity, BigDecimal> getter) {
|
||||||
|
return cargoes.stream().map(getter).filter(Objects::nonNull)
|
||||||
|
.reduce(BigDecimal.ZERO, BigDecimal::add);
|
||||||
|
}
|
||||||
|
|
||||||
|
private String joined(List<OrderCargoEntity> cargoes, Function<OrderCargoEntity, String> getter) {
|
||||||
|
String value = cargoes.stream().map(getter).filter(text -> text != null && !text.isBlank())
|
||||||
|
.distinct().collect(Collectors.joining("、"));
|
||||||
|
return value.isEmpty() ? null : value;
|
||||||
|
}
|
||||||
|
|
||||||
|
private BigDecimal commonUnitPrice(List<OrderCargoEntity> cargoes) {
|
||||||
|
List<BigDecimal> values = cargoes.stream().map(OrderCargoEntity::getUnitDeclaredValue)
|
||||||
|
.filter(Objects::nonNull).distinct().toList();
|
||||||
|
return values.size() == 1 ? values.get(0) : null;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -7,6 +7,30 @@ security:
|
|||||||
- bearerAuth: []
|
- bearerAuth: []
|
||||||
paths:
|
paths:
|
||||||
/api/merchant/v1/orders/first-leg:
|
/api/merchant/v1/orders/first-leg:
|
||||||
|
get:
|
||||||
|
summary: 客户端入库订单聚合列表
|
||||||
|
description: 按当前登录租户分页返回订单、货物汇总、收货方快照及头程入仓编码,需要 merchant:order:list 权限。
|
||||||
|
parameters:
|
||||||
|
- {name: keyword, in: query, required: false, schema: {type: string, maxLength: 64}}
|
||||||
|
- {name: orderNo, in: query, required: false, schema: {type: string, maxLength: 64}}
|
||||||
|
- {name: receivingWarehouseId, in: query, required: false, schema: {type: string, pattern: '^[1-9][0-9]*$'}}
|
||||||
|
- {name: channelName, in: query, required: false, schema: {type: string, maxLength: 128}}
|
||||||
|
- {name: customerContact, in: query, required: false, description: 客户名称、联系人或手机号, schema: {type: string, maxLength: 128}}
|
||||||
|
- {name: customerId, in: query, required: false, schema: {type: string, pattern: '^[1-9][0-9]*$'}}
|
||||||
|
- {name: status, in: query, required: false, schema: {type: string}}
|
||||||
|
- {name: operationStatus, in: query, required: false, description: 操作状态,优先于兼容参数 status, schema: {type: string}}
|
||||||
|
- {name: destinationType, in: query, required: false, schema: {type: string, maxLength: 32}}
|
||||||
|
- {name: destinationWarehouseId, in: query, required: false, schema: {type: string, pattern: '^[1-9][0-9]*$'}}
|
||||||
|
- {name: createdFrom, in: query, required: false, schema: {type: string, format: date-time}}
|
||||||
|
- {name: createdTo, in: query, required: false, schema: {type: string, format: date-time}}
|
||||||
|
- {name: page, in: query, required: false, schema: {type: integer, minimum: 1, default: 1}}
|
||||||
|
- {name: size, in: query, required: false, schema: {type: integer, minimum: 1, maximum: 200, default: 20}}
|
||||||
|
responses:
|
||||||
|
'200':
|
||||||
|
description: 成功或业务失败,响应体 code 为字符串 200 时成功
|
||||||
|
content:
|
||||||
|
application/json:
|
||||||
|
schema: {type: object}
|
||||||
post:
|
post:
|
||||||
summary: 创建订单草稿
|
summary: 创建订单草稿
|
||||||
parameters:
|
parameters:
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ package com.baiyue.order.controller;
|
|||||||
|
|
||||||
import com.baiyue.common.security.AuthenticatedUser;
|
import com.baiyue.common.security.AuthenticatedUser;
|
||||||
import com.baiyue.order.dto.OrderRequests;
|
import com.baiyue.order.dto.OrderRequests;
|
||||||
|
import com.baiyue.order.dto.MerchantInboundOrderQuery;
|
||||||
import org.junit.jupiter.api.DisplayName;
|
import org.junit.jupiter.api.DisplayName;
|
||||||
import org.junit.jupiter.api.Test;
|
import org.junit.jupiter.api.Test;
|
||||||
import org.springframework.security.access.prepost.PreAuthorize;
|
import org.springframework.security.access.prepost.PreAuthorize;
|
||||||
@@ -16,7 +17,7 @@ class OrderControllerPermissionTest {
|
|||||||
@Test
|
@Test
|
||||||
void merchantOrderListAndDetailRequireCorrespondingPermissions() throws Exception {
|
void merchantOrderListAndDetailRequireCorrespondingPermissions() throws Exception {
|
||||||
assertAuthority(MerchantFirstLegOrderController.class, "page", "hasAuthority('merchant:order:list')",
|
assertAuthority(MerchantFirstLegOrderController.class, "page", "hasAuthority('merchant:order:list')",
|
||||||
AuthenticatedUser.class, OrderRequests.QueryRequest.class);
|
AuthenticatedUser.class, MerchantInboundOrderQuery.class);
|
||||||
assertAuthority(MerchantFirstLegOrderController.class, "detail", "hasAuthority('merchant:order:view')",
|
assertAuthority(MerchantFirstLegOrderController.class, "detail", "hasAuthority('merchant:order:view')",
|
||||||
AuthenticatedUser.class, long.class);
|
AuthenticatedUser.class, long.class);
|
||||||
}
|
}
|
||||||
|
|||||||
+55
@@ -0,0 +1,55 @@
|
|||||||
|
package com.baiyue.order.repository;
|
||||||
|
|
||||||
|
import com.baiyue.order.dto.MerchantInboundOrderQuery;
|
||||||
|
import com.baiyue.order.entity.OrderEntity;
|
||||||
|
import com.baiyue.order.entity.OrderStatus;
|
||||||
|
import com.baiyue.order.mapper.OrderCargoMapper;
|
||||||
|
import com.baiyue.order.mapper.OrderChildPurgeMapper;
|
||||||
|
import com.baiyue.order.mapper.OrderIdempotencyRecordMapper;
|
||||||
|
import com.baiyue.order.mapper.OrderInternalNoteMapper;
|
||||||
|
import com.baiyue.order.mapper.OrderMapper;
|
||||||
|
import com.baiyue.order.mapper.OrderPartyMapper;
|
||||||
|
import com.baiyue.order.mapper.OrderStatusHistoryMapper;
|
||||||
|
import com.baiyue.order.mapper.OutboxEventMapper;
|
||||||
|
import com.baomidou.mybatisplus.core.conditions.Wrapper;
|
||||||
|
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||||
|
import com.baomidou.mybatisplus.core.MybatisConfiguration;
|
||||||
|
import com.baomidou.mybatisplus.core.metadata.TableInfoHelper;
|
||||||
|
import org.apache.ibatis.builder.MapperBuilderAssistant;
|
||||||
|
import org.junit.jupiter.api.Test;
|
||||||
|
import org.mockito.ArgumentCaptor;
|
||||||
|
|
||||||
|
import static org.assertj.core.api.Assertions.assertThat;
|
||||||
|
import static org.mockito.ArgumentMatchers.any;
|
||||||
|
import static org.mockito.Mockito.mock;
|
||||||
|
import static org.mockito.Mockito.verify;
|
||||||
|
import static org.mockito.Mockito.when;
|
||||||
|
|
||||||
|
class MerchantInboundOrderQueryRepositoryTest {
|
||||||
|
@Test
|
||||||
|
@SuppressWarnings({"rawtypes", "unchecked"})
|
||||||
|
void 查询始终带租户并覆盖页面筛选条件() {
|
||||||
|
TableInfoHelper.initTableInfo(
|
||||||
|
new MapperBuilderAssistant(new MybatisConfiguration(), "merchant-inbound-query-test"),
|
||||||
|
OrderEntity.class);
|
||||||
|
OrderMapper mapper = mock(OrderMapper.class);
|
||||||
|
when(mapper.selectPage(any(Page.class), any(Wrapper.class))).thenReturn(new Page<>());
|
||||||
|
OrderRepository repository = new OrderRepository(
|
||||||
|
mapper, mock(OrderCargoMapper.class), mock(OrderPartyMapper.class),
|
||||||
|
mock(OrderInternalNoteMapper.class), mock(OrderStatusHistoryMapper.class),
|
||||||
|
mock(OutboxEventMapper.class), mock(OrderChildPurgeMapper.class),
|
||||||
|
mock(OrderIdempotencyRecordMapper.class));
|
||||||
|
MerchantInboundOrderQuery query = new MerchantInboundOrderQuery(
|
||||||
|
"客户", "FL-", 11L, "美森", "13800000000", 30001L, null, OrderStatus.APPROVED,
|
||||||
|
"FBA", 22L, null, null, 1, 20);
|
||||||
|
|
||||||
|
repository.merchantInboundPage(10001L, query);
|
||||||
|
|
||||||
|
ArgumentCaptor<Wrapper<OrderEntity>> captor = ArgumentCaptor.forClass(Wrapper.class);
|
||||||
|
verify(mapper).selectPage(any(Page.class), captor.capture());
|
||||||
|
String sql = captor.getValue().getSqlSegment();
|
||||||
|
assertThat(sql).contains("tenant_id", "order_no", "receiving_warehouse_id", "channel_name",
|
||||||
|
"customer_id", "customer_name", "contact_name", "phone", "status",
|
||||||
|
"destination_type", "destination_warehouse_id");
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,97 @@
|
|||||||
|
package com.baiyue.order.service;
|
||||||
|
|
||||||
|
import com.baiyue.common.core.api.ApiResponse;
|
||||||
|
import com.baiyue.common.core.api.PageResult;
|
||||||
|
import com.baiyue.order.client.FirstlegInboundClient;
|
||||||
|
import com.baiyue.order.dto.MerchantInboundOrderQuery;
|
||||||
|
import com.baiyue.order.entity.OrderCargoEntity;
|
||||||
|
import com.baiyue.order.entity.OrderEntity;
|
||||||
|
import com.baiyue.order.entity.OrderPartyEntity;
|
||||||
|
import com.baiyue.order.entity.OrderStatus;
|
||||||
|
import com.baiyue.order.entity.OrderStatusHistoryEntity;
|
||||||
|
import com.baiyue.order.repository.OrderRepository;
|
||||||
|
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.mockito.Mockito.mock;
|
||||||
|
import static org.mockito.Mockito.verify;
|
||||||
|
import static org.mockito.Mockito.when;
|
||||||
|
|
||||||
|
class MerchantInboundOrderListServiceTest {
|
||||||
|
private final OrderRepository repository = mock(OrderRepository.class);
|
||||||
|
private final FirstlegInboundClient firstleg = mock(FirstlegInboundClient.class);
|
||||||
|
private final MerchantInboundOrderListService service =
|
||||||
|
new MerchantInboundOrderListService(repository, firstleg, "internal-token");
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void 聚合客户端列表所需的订单货物收货方和入仓编码() {
|
||||||
|
MerchantInboundOrderQuery query = new MerchantInboundOrderQuery(
|
||||||
|
null, null, null, null, null, null, null, null, null, null, null, null, 1, 20);
|
||||||
|
OrderEntity order = new OrderEntity();
|
||||||
|
order.setId(77L);
|
||||||
|
order.setOrderNo("FL-77");
|
||||||
|
order.setStatus(OrderStatus.APPROVED);
|
||||||
|
order.setChannelName("美森");
|
||||||
|
order.setDestinationType("FBA");
|
||||||
|
order.setCustomerName("测试客户");
|
||||||
|
order.setShipmentId("FBA-SHIPMENT-77");
|
||||||
|
order.setExpressTrackingNo("TRACK-77");
|
||||||
|
order.setCustomerRemark("客户备注");
|
||||||
|
when(repository.merchantInboundPage(10001L, query))
|
||||||
|
.thenReturn(new PageResult<>(List.of(order), 1, 20, 1, 1));
|
||||||
|
|
||||||
|
OrderCargoEntity first = cargo(1L, 1, 2, 20, "10.000", "9.000", "0.1200", "10.00", "20.00", "A");
|
||||||
|
OrderCargoEntity second = cargo(2L, 2, 3, 30, "15.000", "14.000", "0.1800", "10.00", "30.00", "B");
|
||||||
|
when(repository.findCargoByOrderIds(10001L, List.of(77L))).thenReturn(List.of(first, second));
|
||||||
|
OrderPartyEntity consignee = new OrderPartyEntity();
|
||||||
|
consignee.setOrderId(77L);
|
||||||
|
consignee.setPartyType("RECEIVER");
|
||||||
|
consignee.setCompanyName("收货公司");
|
||||||
|
when(repository.findPartiesByOrderIds(10001L, List.of(77L))).thenReturn(List.of(consignee));
|
||||||
|
OrderStatusHistoryEntity history = new OrderStatusHistoryEntity();
|
||||||
|
history.setOrderId(77L);
|
||||||
|
history.setOperatorId(9L);
|
||||||
|
history.setOperatorName("操作员");
|
||||||
|
when(repository.findHistoryByOrderIds(10001L, List.of(77L))).thenReturn(List.of(history));
|
||||||
|
when(firstleg.references(org.mockito.ArgumentMatchers.eq("internal-token"),
|
||||||
|
org.mockito.ArgumentMatchers.any())).thenReturn(ApiResponse.success(List.of(
|
||||||
|
new FirstlegInboundClient.InboundReference(77L, 88L, "RK-77", "WAIT_MEASURE"))));
|
||||||
|
|
||||||
|
var row = service.page(10001L, query).records().get(0);
|
||||||
|
|
||||||
|
assertThat(row.inboundCode()).isEqualTo("RK-77");
|
||||||
|
assertThat(row.packageCount()).isEqualTo(5);
|
||||||
|
assertThat(row.totalQuantity()).isEqualTo(50);
|
||||||
|
assertThat(row.totalGrossWeightKg()).isEqualByComparingTo("25.000");
|
||||||
|
assertThat(row.totalNetWeightKg()).isEqualByComparingTo("23.000");
|
||||||
|
assertThat(row.totalVolumeCbm()).isEqualByComparingTo("0.3000");
|
||||||
|
assertThat(row.customsDeclaredAmount()).isEqualByComparingTo("50.00");
|
||||||
|
assertThat(row.customsDeclaredUnitPrice()).isEqualByComparingTo("10.00");
|
||||||
|
assertThat(row.specificationModel()).isEqualTo("A、B");
|
||||||
|
assertThat(row.receivingCompanyName()).isEqualTo("收货公司");
|
||||||
|
assertThat(row.operatorName()).isEqualTo("操作员");
|
||||||
|
assertThat(row.cargoes()).hasSize(2);
|
||||||
|
verify(repository).merchantInboundPage(10001L, query);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static OrderCargoEntity cargo(Long id, int itemNo, int packages, int quantity,
|
||||||
|
String gross, String net, String volume,
|
||||||
|
String unitPrice, String amount, String model) {
|
||||||
|
OrderCargoEntity cargo = new OrderCargoEntity();
|
||||||
|
cargo.setId(id);
|
||||||
|
cargo.setOrderId(77L);
|
||||||
|
cargo.setItemNo(itemNo);
|
||||||
|
cargo.setPackageCount(packages);
|
||||||
|
cargo.setTotalQuantity(quantity);
|
||||||
|
cargo.setGrossWeightKg(new BigDecimal(gross));
|
||||||
|
cargo.setNetWeightKg(new BigDecimal(net));
|
||||||
|
cargo.setVolumeCbm(new BigDecimal(volume));
|
||||||
|
cargo.setUnitDeclaredValue(new BigDecimal(unitPrice));
|
||||||
|
cargo.setDeclaredValue(new BigDecimal(amount));
|
||||||
|
cargo.setModel(model);
|
||||||
|
return cargo;
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user