Merge branch 'test' of http://8.163.30.128:10082/java-project/baiyue-firstleg into test-01
This commit is contained in:
+10
-5
@@ -31,11 +31,11 @@ import org.springframework.web.bind.annotation.PutMapping;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 平台端头程订单管理接口,在明确的目标租户范围内提供查询、审核和履约状态流转能力。
|
||||
* 平台端头程订单管理接口,提供跨租户列表查询,并在明确的目标租户范围内执行详情查询和状态流转。
|
||||
*/
|
||||
@Tag(
|
||||
name = "Platform first-leg orders / 平台头程订单",
|
||||
description = "Platform lifecycle management for orders in an explicit target tenant. / 平台端针对明确目标租户管理头程订单生命周期。"
|
||||
description = "Platform review queue across tenants; detail and lifecycle actions require an explicit target tenant. / 平台端跨租户审核队列;详情和生命周期操作需要明确目标租户。"
|
||||
)
|
||||
@RestController
|
||||
@RequestMapping("/api/platform/v1/orders/first-leg")
|
||||
@@ -98,7 +98,7 @@ public class PlatformFirstLegOrderController {
|
||||
return ApiResponse.success(null);
|
||||
}
|
||||
|
||||
@Operation(summary = "Tenant order query / 租户订单查询", description = "Queries a page of first-leg orders in the explicit target tenant. / 分页查询明确目标租户下的头程订单。")
|
||||
@Operation(summary = "Platform order query / 平台订单查询", description = "Queries all tenant orders when tenantId is omitted, or filters one tenant when supplied. / tenantId 省略时分页查询全部客户租户订单,传入时仅查询指定租户。")
|
||||
@ApiResponses({
|
||||
@io.swagger.v3.oas.annotations.responses.ApiResponse(responseCode = "200", description = "Query succeeded / 查询成功"),
|
||||
@io.swagger.v3.oas.annotations.responses.ApiResponse(responseCode = "403", description = "Platform scope required / 需要平台端权限")
|
||||
@@ -107,9 +107,14 @@ public class PlatformFirstLegOrderController {
|
||||
@PreAuthorize("hasAuthority('platform:order:list')")
|
||||
public ApiResponse<PageResult<OrderEntity>> page(
|
||||
@AuthenticationPrincipal AuthenticatedUser user,
|
||||
@Parameter(description = "Target tenant ID / 目标租户 ID", example = "10001", required = true) @RequestParam long tenantId,
|
||||
@Parameter(description = "Optional target tenant filter / 可选的目标租户筛选", example = "10001")
|
||||
@RequestParam(required = false) Long tenantId,
|
||||
@Valid OrderRequests.QueryRequest query) {
|
||||
return ApiResponse.success(service.page(OrderScopeGuard.platform(user, tenantId), query));
|
||||
OrderScopeGuard.platform(user);
|
||||
if (tenantId != null) {
|
||||
OrderScopeGuard.platform(user, tenantId);
|
||||
}
|
||||
return ApiResponse.success(service.page(tenantId, query));
|
||||
}
|
||||
|
||||
@GetMapping("/tenant-counts")
|
||||
|
||||
@@ -44,10 +44,10 @@ public final class OrderRequests {
|
||||
LocalDate expectedShipDate,
|
||||
@Schema(description = "Customer remark / 客户备注", example = "Notify before pickup / 提货前联系", maxLength = 1000)
|
||||
@Size(max = 1000) String customerRemark,
|
||||
@Schema(description = "Sender information / 发货方信息", requiredMode = Schema.RequiredMode.REQUIRED)
|
||||
@NotNull @Valid Party sender,
|
||||
@Schema(description = "Receiver information / 收货方信息", requiredMode = Schema.RequiredMode.REQUIRED)
|
||||
@NotNull @Valid Party receiver,
|
||||
@Schema(description = "Sender information; required when pickupMethod is PICKUP / 发货方信息,取货方式为 PICKUP 时必填")
|
||||
@Valid Party sender,
|
||||
@Schema(description = "Receiver information; required for PRIVATE destination / 收货方信息,私人地址目的地时必填")
|
||||
@Valid Party receiver,
|
||||
@Schema(description = "Cargo lines / 货物明细", requiredMode = Schema.RequiredMode.REQUIRED)
|
||||
@NotEmpty @Valid List<Cargo> cargoes,
|
||||
@NotBlank @Pattern(regexp = "SELF_EXPRESS|PICKUP|SELF_TRUCK") String pickupMethod,
|
||||
|
||||
@@ -73,9 +73,9 @@ public class OrderRepository {
|
||||
.eq(OrderEntity::getId, orderId));
|
||||
}
|
||||
|
||||
public PageResult<OrderEntity> page(long tenantId, OrderRequests.QueryRequest query) {
|
||||
public PageResult<OrderEntity> page(Long tenantId, OrderRequests.QueryRequest query) {
|
||||
LambdaQueryWrapper<OrderEntity> wrapper = new LambdaQueryWrapper<OrderEntity>()
|
||||
.eq(OrderEntity::getTenantId, tenantId)
|
||||
.eq(tenantId != null, OrderEntity::getTenantId, tenantId)
|
||||
.eq(query.status() != null, OrderEntity::getStatus, query.status())
|
||||
.eq(query.customerId() != null, OrderEntity::getCustomerId, query.customerId())
|
||||
.eq(query.destinationWarehouseId() != null, OrderEntity::getDestinationWarehouseId, query.destinationWarehouseId())
|
||||
|
||||
@@ -106,7 +106,7 @@ public class OrderApplicationService {
|
||||
completeIdempotency(idempotency, id);
|
||||
}
|
||||
|
||||
public PageResult<OrderEntity> page(long tenantId, OrderRequests.QueryRequest query) { return repository.page(tenantId, query); }
|
||||
public PageResult<OrderEntity> page(Long tenantId, OrderRequests.QueryRequest query) { return repository.page(tenantId, query); }
|
||||
|
||||
public List<TenantOrderCountResponse> countByTenantIds(List<Long> tenantIds) {
|
||||
var counts = repository.countByTenantIds(tenantIds);
|
||||
@@ -145,6 +145,12 @@ public class OrderApplicationService {
|
||||
}
|
||||
|
||||
private void validatePrototypeFields(OrderRequests.SaveRequest request) {
|
||||
if ("PICKUP".equals(request.pickupMethod()) && request.sender() == null) {
|
||||
throw new BizException("上门提货时必须填写发货信息");
|
||||
}
|
||||
if ("PRIVATE".equals(request.destinationType()) && request.receiver() == null) {
|
||||
throw new BizException("私人地址必须填写收货信息");
|
||||
}
|
||||
if ("FBA".equals(request.destinationType())) {
|
||||
if (!StringUtils.hasText(request.amazonWarehouseCode()) || !StringUtils.hasText(request.shipmentId())
|
||||
|| !StringUtils.hasText(request.referenceId())) {
|
||||
@@ -168,6 +174,13 @@ public class OrderApplicationService {
|
||||
}
|
||||
var cargoes = repository.findCargo(tenantId, order.getId());
|
||||
if (cargoes == null || cargoes.isEmpty()) throw new BizException("At least one cargo line is required");
|
||||
var parties = repository.findParties(tenantId, order.getId());
|
||||
if ("PICKUP".equals(order.getPickupMethod()) && !hasParty(parties, "SENDER")) {
|
||||
throw new BizException("上门提货时必须填写发货信息");
|
||||
}
|
||||
if ("PRIVATE".equals(order.getDestinationType()) && !hasParty(parties, "RECEIVER")) {
|
||||
throw new BizException("私人地址必须填写收货信息");
|
||||
}
|
||||
if ("FBA".equals(order.getDestinationType())) {
|
||||
if (!StringUtils.hasText(order.getAmazonWarehouseCode()) || !StringUtils.hasText(order.getShipmentId())
|
||||
|| !StringUtils.hasText(order.getReferenceId())) {
|
||||
@@ -181,6 +194,11 @@ public class OrderApplicationService {
|
||||
}
|
||||
}
|
||||
|
||||
private boolean hasParty(List<OrderPartyEntity> parties, String partyType) {
|
||||
return parties != null && parties.stream()
|
||||
.anyMatch(party -> party != null && partyType.equals(party.getPartyType()));
|
||||
}
|
||||
|
||||
private OrderEntity require(long tenantId, long id) {
|
||||
OrderEntity order = repository.findOwned(tenantId, id);
|
||||
if (order == null) throw new BizException(com.baiyue.common.core.api.ResultCode.NOT_FOUND, "Order not found");
|
||||
@@ -272,7 +290,8 @@ public class OrderApplicationService {
|
||||
};
|
||||
}
|
||||
private void apply(OrderEntity order, OrderRequests.SaveRequest request, OrderMasterDataGuard.Snapshots snapshots) {
|
||||
order.setCustomerId(snapshots.partner().id()); order.setCustomerName(snapshots.partner().partnerName());
|
||||
order.setCustomerId(snapshots.partner() == null ? null : snapshots.partner().id());
|
||||
order.setCustomerName(snapshots.partner() == null ? request.customerName() : snapshots.partner().partnerName());
|
||||
order.setTransportMode(request.transportMode()); order.setTradeTerm(request.tradeTerm());
|
||||
order.setDestinationCountryCode(snapshots.destination() == null ? request.destinationCountryCode()
|
||||
: snapshots.destination().warehouse().countryCode());
|
||||
@@ -324,8 +343,8 @@ public class OrderApplicationService {
|
||||
item.setProductUsage(cargo.usage()); item.setModel(cargo.model()); item.setBrand(cargo.brand());
|
||||
item.setCreatedBy(userId); item.setUpdatedBy(userId); repository.insertCargo(item);
|
||||
}
|
||||
saveParty(tenantId, userId, orderId, "SENDER", request.sender());
|
||||
saveParty(tenantId, userId, orderId, "RECEIVER", request.receiver());
|
||||
if (request.sender() != null) saveParty(tenantId, userId, orderId, "SENDER", request.sender());
|
||||
if (request.receiver() != null) saveParty(tenantId, userId, orderId, "RECEIVER", request.receiver());
|
||||
}
|
||||
private void saveParty(long tenantId, long userId, long orderId, String type, OrderRequests.Party party) {
|
||||
OrderPartyEntity item = new OrderPartyEntity();
|
||||
|
||||
@@ -28,9 +28,8 @@ public class OrderMasterDataGuard {
|
||||
this.warehouses=warehouses; this.partners=partners; this.token=token;
|
||||
}
|
||||
public Snapshots validate(long tenantId, OrderRequests.SaveRequest request) {
|
||||
if (request.customerId() == null) throw new BizException(ResultCode.VALIDATION_FAILED, "必须选择往来单位");
|
||||
try {
|
||||
var partner=loadPartner(tenantId,request.customerId());
|
||||
PartnerClient.Partner partner=request.customerId()==null ? null : loadPartner(tenantId,request.customerId());
|
||||
var receiving=loadWarehouse(request.receivingWarehouseId(),"收货仓库");
|
||||
requireWarehouseType(receiving, "DOMESTIC", "收货仓库");
|
||||
if (receiving.addresses()==null || receiving.addresses().stream().noneMatch(Objects::nonNull))
|
||||
@@ -62,8 +61,7 @@ public class OrderMasterDataGuard {
|
||||
public void validatePersisted(long tenantId, Long partnerId, Long receivingWarehouseId,
|
||||
Long destinationWarehouseId, String destinationType) {
|
||||
try {
|
||||
if (partnerId==null) throw new BizException(ResultCode.NOT_FOUND,"往来单位已停用或不可用");
|
||||
loadPartner(tenantId,partnerId);
|
||||
if (partnerId!=null) loadPartner(tenantId,partnerId);
|
||||
if (receivingWarehouseId==null) throw new BizException(ResultCode.NOT_FOUND,"收货仓库已停用或不可用");
|
||||
WarehouseClient.Detail receiving=loadWarehouse(receivingWarehouseId,"收货仓库");
|
||||
requireWarehouseType(receiving,"DOMESTIC","收货仓库");
|
||||
|
||||
@@ -5,6 +5,7 @@ import com.baiyue.common.core.api.ResultCode; import com.baiyue.common.core.exce
|
||||
*/
|
||||
public final class OrderScopeGuard { private OrderScopeGuard(){}
|
||||
public static long merchant(AuthenticatedUser u){requireApp(u,"MERCHANT");if(u.tenantId()==null||u.tenantId()<=0)throw new BizException(ResultCode.FORBIDDEN,"Merchant tenant is required");return u.tenantId();}
|
||||
public static void platform(AuthenticatedUser u){requireApp(u,"PLATFORM");}
|
||||
public static long platform(AuthenticatedUser u,long targetTenantId){requireApp(u,"PLATFORM");if(targetTenantId<=0)throw new BizException(ResultCode.BAD_REQUEST,"Target tenant is required");return targetTenantId;}
|
||||
private static void requireApp(AuthenticatedUser u,String expected){if(u==null||!expected.equals(u.appCode()))throw new BizException(ResultCode.FORBIDDEN,"Wrong application scope");}
|
||||
}
|
||||
|
||||
@@ -27,6 +27,18 @@ paths:
|
||||
responses:
|
||||
'200': {description: 成功或业务失败,按响应体 code 判断}
|
||||
/api/platform/v1/orders/first-leg:
|
||||
get:
|
||||
summary: 平台分页查询头程订单
|
||||
description: tenantId 省略时查询全部客户租户订单,传入时仅查询指定租户。
|
||||
parameters:
|
||||
- name: tenantId
|
||||
in: query
|
||||
required: false
|
||||
description: 可选的目标租户筛选
|
||||
schema: {type: integer, format: int64, minimum: 1}
|
||||
responses:
|
||||
'200': {description: 查询成功或业务失败,按响应体 code 判断}
|
||||
'403': {description: 需要 platform:order:list 权限和平台身份}
|
||||
post:
|
||||
summary: 平台代客创建订单草稿
|
||||
parameters:
|
||||
|
||||
@@ -24,7 +24,7 @@ class OrderControllerPermissionTest {
|
||||
@Test
|
||||
void platformOrderListAndDetailUseConfiguredListPermission() throws Exception {
|
||||
assertAuthority(PlatformFirstLegOrderController.class, "page", "hasAuthority('platform:order:list')",
|
||||
AuthenticatedUser.class, long.class, OrderRequests.QueryRequest.class);
|
||||
AuthenticatedUser.class, Long.class, OrderRequests.QueryRequest.class);
|
||||
assertAuthority(PlatformFirstLegOrderController.class, "detail", "hasAuthority('platform:order:list')",
|
||||
AuthenticatedUser.class, long.class, long.class);
|
||||
assertAuthority(PlatformFirstLegOrderController.class, "tenantCounts", "hasAuthority('platform:order:list')",
|
||||
|
||||
@@ -0,0 +1,72 @@
|
||||
package com.baiyue.order.controller;
|
||||
|
||||
import com.baiyue.common.core.exception.BizException;
|
||||
import com.baiyue.common.security.AuthenticatedUser;
|
||||
import com.baiyue.order.dto.OrderRequests;
|
||||
import com.baiyue.order.service.OrderApplicationService;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.springframework.test.util.ReflectionTestUtils;
|
||||
|
||||
import java.util.Set;
|
||||
|
||||
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.verifyNoInteractions;
|
||||
|
||||
class PlatformOrderPageControllerTest {
|
||||
private final OrderRequests.QueryRequest query = new OrderRequests.QueryRequest(
|
||||
null, null, null, null, null, null, 1, 20);
|
||||
|
||||
@Test
|
||||
void omittedTenantQueriesAcrossAllTenantsForPlatformUser() {
|
||||
OrderApplicationService service = mock(OrderApplicationService.class);
|
||||
PlatformFirstLegOrderController controller = controller(service);
|
||||
|
||||
controller.page(user("PLATFORM"), null, query);
|
||||
|
||||
verify(service).page(null, query);
|
||||
}
|
||||
|
||||
@Test
|
||||
void suppliedTenantFiltersOneTenantForPlatformUser() {
|
||||
OrderApplicationService service = mock(OrderApplicationService.class);
|
||||
PlatformFirstLegOrderController controller = controller(service);
|
||||
|
||||
controller.page(user("PLATFORM"), 2084455952401629185L, query);
|
||||
|
||||
verify(service).page(2084455952401629185L, query);
|
||||
}
|
||||
|
||||
@Test
|
||||
void invalidTenantFilterIsRejectedBeforeQuery() {
|
||||
OrderApplicationService service = mock(OrderApplicationService.class);
|
||||
PlatformFirstLegOrderController controller = controller(service);
|
||||
|
||||
assertThatThrownBy(() -> controller.page(user("PLATFORM"), 0L, query))
|
||||
.isInstanceOf(BizException.class)
|
||||
.hasMessageContaining("Target tenant is required");
|
||||
verifyNoInteractions(service);
|
||||
}
|
||||
|
||||
@Test
|
||||
void merchantCannotUseCrossTenantPlatformList() {
|
||||
OrderApplicationService service = mock(OrderApplicationService.class);
|
||||
PlatformFirstLegOrderController controller = controller(service);
|
||||
|
||||
assertThatThrownBy(() -> controller.page(user("MERCHANT"), null, query))
|
||||
.isInstanceOf(BizException.class)
|
||||
.hasMessageContaining("Wrong application scope");
|
||||
verifyNoInteractions(service);
|
||||
}
|
||||
|
||||
private PlatformFirstLegOrderController controller(OrderApplicationService service) {
|
||||
PlatformFirstLegOrderController controller = new PlatformFirstLegOrderController();
|
||||
ReflectionTestUtils.setField(controller, "service", service);
|
||||
return controller;
|
||||
}
|
||||
|
||||
private AuthenticatedUser user(String appCode) {
|
||||
return new AuthenticatedUser(1L, null, null, null, "operator", appCode, "WEB", Set.of());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,56 @@
|
||||
package com.baiyue.order.repository;
|
||||
|
||||
import com.baiyue.order.dto.OrderRequests;
|
||||
import com.baiyue.order.entity.OrderEntity;
|
||||
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 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 PlatformOrderPageRepositoryTest {
|
||||
private final OrderRequests.QueryRequest query = new OrderRequests.QueryRequest(
|
||||
null, null, null, null, null, null, 1, 20);
|
||||
|
||||
@Test
|
||||
@SuppressWarnings({"rawtypes", "unchecked"})
|
||||
void tenantPredicateIsAddedOnlyWhenFilterIsSupplied() {
|
||||
OrderMapper mapper = mock(OrderMapper.class);
|
||||
when(mapper.selectPage(any(Page.class), any(Wrapper.class))).thenReturn(new Page<>());
|
||||
OrderRepository repository = repository(mapper);
|
||||
|
||||
repository.page(null, query);
|
||||
repository.page(20002L, query);
|
||||
|
||||
ArgumentCaptor<Wrapper<OrderEntity>> wrapperCaptor = ArgumentCaptor.forClass(Wrapper.class);
|
||||
verify(mapper, org.mockito.Mockito.times(2)).selectPage(any(Page.class), wrapperCaptor.capture());
|
||||
assertThat(wrapperCaptor.getAllValues().get(0).getExpression().getNormal()).isEmpty();
|
||||
assertThat(wrapperCaptor.getAllValues().get(1).getExpression().getNormal()).isNotEmpty();
|
||||
}
|
||||
|
||||
private OrderRepository repository(OrderMapper mapper) {
|
||||
return new OrderRepository(
|
||||
mapper,
|
||||
mock(OrderCargoMapper.class),
|
||||
mock(OrderPartyMapper.class),
|
||||
mock(OrderInternalNoteMapper.class),
|
||||
mock(OrderStatusHistoryMapper.class),
|
||||
mock(OutboxEventMapper.class),
|
||||
mock(OrderChildPurgeMapper.class),
|
||||
mock(OrderIdempotencyRecordMapper.class)
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -6,6 +6,7 @@ import com.baiyue.order.client.PartnerClient;
|
||||
import com.baiyue.order.client.WarehouseClient;
|
||||
import com.baiyue.order.dto.OrderRequests;
|
||||
import com.baiyue.order.entity.OrderEntity;
|
||||
import com.baiyue.order.entity.OrderCargoEntity;
|
||||
import com.baiyue.order.entity.OrderStatus;
|
||||
import com.baiyue.order.repository.OrderRepository;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
@@ -98,6 +99,68 @@ class OrderApplicationServiceStateTest {
|
||||
verify(repository,never()).saveOrder(any());
|
||||
}
|
||||
|
||||
@Test
|
||||
void publicDestinationCanBeSavedWithoutPartnerSenderOrReceiver() {
|
||||
OrderRepository repository = mock(OrderRepository.class);
|
||||
OrderEligibilityGuard eligibility = mock(OrderEligibilityGuard.class);
|
||||
OrderMasterDataGuard masterData = mock(OrderMasterDataGuard.class);
|
||||
OrderRequests.SaveRequest request = request(null, "SELF_EXPRESS", null, null, "OVERSEAS");
|
||||
when(masterData.validate(20002L, request)).thenReturn(snapshots(null));
|
||||
when(repository.completeIdempotency(any(), anyLong())).thenReturn(1);
|
||||
|
||||
service(repository, eligibility, masterData)
|
||||
.createDraft(20002L, 2L, request, "public-destination-no-parties");
|
||||
|
||||
verify(repository).insertOrder(argThat(order -> order.getCustomerId() == null
|
||||
&& "当前企业".equals(order.getCustomerName())));
|
||||
verify(repository, never()).insertParty(any());
|
||||
}
|
||||
|
||||
@Test
|
||||
void pickupStillRequiresSender() {
|
||||
OrderRepository repository = mock(OrderRepository.class);
|
||||
OrderMasterDataGuard masterData = mock(OrderMasterDataGuard.class);
|
||||
OrderRequests.SaveRequest request = request(null, "PICKUP", null, null, "OVERSEAS");
|
||||
|
||||
assertThatThrownBy(() -> service(repository, mock(OrderEligibilityGuard.class), masterData)
|
||||
.createDraft(20002L, 2L, request, "pickup-without-sender"))
|
||||
.isInstanceOf(BizException.class)
|
||||
.hasMessageContaining("上门提货时必须填写发货信息");
|
||||
|
||||
verifyNoInteractions(masterData);
|
||||
}
|
||||
|
||||
@Test
|
||||
void privateDestinationStillRequiresReceiver() {
|
||||
OrderRepository repository = mock(OrderRepository.class);
|
||||
OrderMasterDataGuard masterData = mock(OrderMasterDataGuard.class);
|
||||
OrderRequests.SaveRequest request = request(null, "SELF_EXPRESS", null, null, "PRIVATE");
|
||||
|
||||
assertThatThrownBy(() -> service(repository, mock(OrderEligibilityGuard.class), masterData)
|
||||
.createDraft(20002L, 2L, request, "private-without-receiver"))
|
||||
.isInstanceOf(BizException.class)
|
||||
.hasMessageContaining("私人地址必须填写收货信息");
|
||||
|
||||
verifyNoInteractions(masterData);
|
||||
}
|
||||
|
||||
@Test
|
||||
void submittingPersistedPickupDraftRequiresSenderSnapshot() {
|
||||
OrderRepository repository = mock(OrderRepository.class);
|
||||
OrderEntity order = persistedDraft("PICKUP", "OVERSEAS");
|
||||
OrderCargoEntity cargo = new OrderCargoEntity();
|
||||
when(repository.findOwned(20002L, 1L)).thenReturn(order);
|
||||
when(repository.findCargo(20002L, 1L)).thenReturn(List.of(cargo));
|
||||
when(repository.findParties(20002L, 1L)).thenReturn(List.of());
|
||||
|
||||
assertThatThrownBy(() -> service(repository, mock(OrderEligibilityGuard.class), mock(OrderMasterDataGuard.class))
|
||||
.transit(20002L, 2L, "u", 1L, OrderStatus.SUBMITTED, null))
|
||||
.isInstanceOf(BizException.class)
|
||||
.hasMessageContaining("上门提货时必须填写发货信息");
|
||||
|
||||
verify(repository, never()).saveOrder(any());
|
||||
}
|
||||
|
||||
private OrderApplicationService service(OrderRepository repository, OrderEligibilityGuard eligibility,
|
||||
OrderMasterDataGuard masterData) {
|
||||
OrderApplicationService service = new OrderApplicationService();
|
||||
@@ -121,12 +184,44 @@ class OrderApplicationServiceStateTest {
|
||||
"BUY_DECLARATION", "LCL", false, "OVERSEAS", null, null, null);
|
||||
}
|
||||
|
||||
private OrderRequests.SaveRequest request(Long customerId, String pickupMethod,
|
||||
OrderRequests.Party sender, OrderRequests.Party receiver,
|
||||
String destinationType) {
|
||||
var cargo = new OrderRequests.Cargo(
|
||||
"货物", null, "CARTON", 1, BigDecimal.ONE, BigDecimal.ONE,
|
||||
null, null, null, null, null, false, null, null, null, null,
|
||||
null, null, null, null, null, null, null, null, null);
|
||||
return new OrderRequests.SaveRequest(
|
||||
customerId, "当前企业", "SEA", null, "US", null, "目的仓", null, null,
|
||||
sender, receiver, List.of(cargo), pickupMethod, 8L, "收货仓", "CH", "渠道",
|
||||
"BUY_DECLARATION", "LCL", false, destinationType, null, null, null);
|
||||
}
|
||||
|
||||
private OrderMasterDataGuard.Snapshots snapshots() {
|
||||
var partner = new PartnerClient.Partner(7L, 10001L, "客户", "ACTIVE", "SHIPPER", List.of("SHIPPER"));
|
||||
return snapshots(new PartnerClient.Partner(7L, 10001L, "客户", "ACTIVE", "SHIPPER", List.of("SHIPPER")));
|
||||
}
|
||||
|
||||
private OrderMasterDataGuard.Snapshots snapshots(PartnerClient.Partner partner) {
|
||||
var warehouse = new WarehouseClient.Warehouse(8L, 10001L, "CN-SZX-01", "收货仓", "DOMESTIC", "CN", "ACTIVE");
|
||||
var address = new WarehouseClient.Address("CN", "广东", "深圳", "南山", "518000", "测试路1号", null);
|
||||
var capability = new WarehouseClient.Capability("RECEIVING", true, LocalTime.of(16, 0));
|
||||
var receiving = new WarehouseClient.Detail(warehouse, List.of(address), List.of(capability));
|
||||
return new OrderMasterDataGuard.Snapshots(partner, receiving, null);
|
||||
}
|
||||
|
||||
private OrderEntity persistedDraft(String pickupMethod, String destinationType) {
|
||||
OrderEntity order = new OrderEntity();
|
||||
order.setId(1L);
|
||||
order.setTenantId(20002L);
|
||||
order.setStatus(OrderStatus.DRAFT);
|
||||
order.setPickupMethod(pickupMethod);
|
||||
order.setReceivingWarehouseId(8L);
|
||||
order.setReceivingWarehouseName("收货仓");
|
||||
order.setChannelCode("CH");
|
||||
order.setChannelName("渠道");
|
||||
order.setTaxMode("BUY_DECLARATION");
|
||||
order.setCustomsInspection(false);
|
||||
order.setDestinationType(destinationType);
|
||||
return order;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -168,6 +168,19 @@ class OrderMasterDataGuardTest {
|
||||
verify(warehouses).active("token",PUBLIC_TENANT_ID,8);
|
||||
}
|
||||
@Test
|
||||
void orderWithoutPartnerUsesPublicWarehouseWithoutPartnerLookup() {
|
||||
WarehouseClient warehouses=mock(WarehouseClient.class); PartnerClient partners=mock(PartnerClient.class);
|
||||
when(warehouses.active("token",PUBLIC_TENANT_ID,8)).thenReturn(ApiResponse.success(
|
||||
warehouse(8L,"DOMESTIC",true)));
|
||||
|
||||
var result=new OrderMasterDataGuard(warehouses,partners,"token")
|
||||
.validate(20002,request(null,8L));
|
||||
|
||||
assertThat(result.partner()).isNull();
|
||||
verifyNoInteractions(partners);
|
||||
verify(warehouses).active("token",PUBLIC_TENANT_ID,8);
|
||||
}
|
||||
@Test
|
||||
void fbaDestinationMustReferenceMatchingPublicWarehouse() {
|
||||
WarehouseClient warehouses=mock(WarehouseClient.class); PartnerClient partners=mock(PartnerClient.class);
|
||||
when(partners.active("token",20002,7)).thenReturn(ApiResponse.success(
|
||||
|
||||
@@ -0,0 +1,27 @@
|
||||
package com.baiyue.order.service;
|
||||
|
||||
import com.baiyue.order.dto.OrderRequests;
|
||||
import com.baiyue.order.repository.OrderRepository;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.springframework.test.util.ReflectionTestUtils;
|
||||
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.verify;
|
||||
|
||||
class PlatformOrderPageServiceTest {
|
||||
private final OrderRequests.QueryRequest query = new OrderRequests.QueryRequest(
|
||||
null, null, null, null, null, null, 1, 20);
|
||||
|
||||
@Test
|
||||
void passesOptionalTenantScopeToRepository() {
|
||||
OrderRepository repository = mock(OrderRepository.class);
|
||||
OrderApplicationService service = new OrderApplicationService();
|
||||
ReflectionTestUtils.setField(service, "repository", repository);
|
||||
|
||||
service.page(null, query);
|
||||
service.page(20002L, query);
|
||||
|
||||
verify(repository).page(null, query);
|
||||
verify(repository).page(20002L, query);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user