This commit is contained in:
2026-08-04 11:14:42 +08:00
parent 0fe129bba7
commit da9aa9515e
14 changed files with 135 additions and 28 deletions
@@ -12,7 +12,8 @@ public interface WarehouseClient {
ApiResponse<Detail> active(@RequestHeader("X-Internal-Service-Token") String token,
@PathVariable("tenantId") long tenantId, @PathVariable("id") long id);
record Detail(Warehouse warehouse, List<Address> addresses, List<Capability> capabilities) { }
record Warehouse(Long id, Long tenantId, String warehouseName, String status) { }
record Warehouse(Long id, Long tenantId, String warehouseCode, String warehouseName,
String warehouseType, String countryCode, String status) { }
record Address(String countryCode, String stateProvince, String city, String district,
String postalCode, String addressLine1, String addressLine2) { }
record Capability(String capabilityCode, Boolean enabled, LocalTime cutoffTime) { }
@@ -81,7 +81,7 @@ public class OrderApplicationService {
if (target == OrderStatus.SUBMITTED) {
validatePersistedPrototypeFields(tenantId, order);
masterDataGuard.validatePersisted(tenantId, order.getCustomerId(), order.getReceivingWarehouseId(),
order.getDestinationWarehouseId());
order.getDestinationWarehouseId(), order.getDestinationType());
}
if ((target == OrderStatus.REJECTED || target == OrderStatus.CANCELLED) && !StringUtils.hasText(reason)) {
throw new BizException("Reason is required");
@@ -274,7 +274,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.setTransportMode(request.transportMode()); order.setTradeTerm(request.tradeTerm());
order.setDestinationCountryCode(request.destinationCountryCode());
order.setDestinationCountryCode(snapshots.destination() == null ? request.destinationCountryCode()
: snapshots.destination().warehouse().countryCode());
order.setDestinationWarehouseId(request.destinationWarehouseId());
order.setDestinationWarehouseName(snapshots.destination() == null ? request.destinationWarehouseName()
: snapshots.destination().warehouse().warehouseName());
@@ -286,7 +287,9 @@ public class OrderApplicationService {
order.setChannelCode(request.channelCode());
order.setChannelName(request.channelName()); order.setTaxMode(request.taxMode());
order.setContainerMode(request.containerMode()); order.setCustomsInspection(request.customsInspection());
order.setDestinationType(request.destinationType()); order.setAmazonWarehouseCode(request.amazonWarehouseCode());
order.setDestinationType(request.destinationType());
order.setAmazonWarehouseCode("FBA".equals(request.destinationType()) && snapshots.destination() != null
? snapshots.destination().warehouse().warehouseCode() : request.amazonWarehouseCode());
order.setShipmentId(request.shipmentId()); order.setReferenceId(request.referenceId());
}
private String formatAddress(com.baiyue.order.client.WarehouseClient.Detail detail) {
@@ -21,6 +21,8 @@ public class OrderMasterDataGuard {
private final WarehouseClient warehouses;
private final PartnerClient partners;
private final String token;
@Value("${baiyue.warehouse.public-tenant-id:10001}")
private long publicTenantId = 10001L;
public OrderMasterDataGuard(WarehouseClient warehouses, PartnerClient partners,
@Value("${baiyue.security.internal-service-token}") String token) {
this.warehouses=warehouses; this.partners=partners; this.token=token;
@@ -29,15 +31,24 @@ public class OrderMasterDataGuard {
if (request.customerId() == null) throw new BizException(ResultCode.VALIDATION_FAILED, "必须选择往来单位");
try {
var partner=loadPartner(tenantId,request.customerId());
var receiving=loadWarehouse(tenantId,request.receivingWarehouseId(),"收货仓库");
var receiving=loadWarehouse(request.receivingWarehouseId(),"收货仓库");
requireWarehouseType(receiving, "DOMESTIC", "收货仓库");
if (receiving.addresses()==null || receiving.addresses().stream().noneMatch(Objects::nonNull))
throw new BizException(ResultCode.VALIDATION_FAILED,"收货仓库未配置地址");
if (receiving.capabilities()==null || receiving.capabilities().stream().noneMatch(c ->
c != null && "RECEIVING".equals(c.capabilityCode()) && Boolean.TRUE.equals(c.enabled())))
throw new BizException(ResultCode.VALIDATION_FAILED,"仓库未启用收货能力");
WarehouseClient.Detail destination=null;
if (request.destinationWarehouseId()!=null) {
destination=loadWarehouse(tenantId,request.destinationWarehouseId(),"目的仓库");
if ("PRIVATE".equals(request.destinationType())) {
if (request.destinationWarehouseId()!=null) {
throw new BizException(ResultCode.VALIDATION_FAILED,"私人地址不能引用公共仓库");
}
} else {
if (request.destinationWarehouseId()==null) {
throw new BizException(ResultCode.VALIDATION_FAILED,"请选择平台维护的目的仓库");
}
destination=loadWarehouse(request.destinationWarehouseId(),"目的仓库");
requireWarehouseType(destination, request.destinationType(), "目的仓库");
}
return new Snapshots(partner,receiving,destination);
} catch (FeignException exception) {
@@ -48,13 +59,21 @@ public class OrderMasterDataGuard {
throw downstreamFailure(exception);
}
}
public void validatePersisted(long tenantId, Long partnerId, Long receivingWarehouseId, Long destinationWarehouseId) {
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 (receivingWarehouseId==null) throw new BizException(ResultCode.NOT_FOUND,"收货仓库已停用或不可用");
loadWarehouse(tenantId,receivingWarehouseId,"收货仓库");
if (destinationWarehouseId!=null) loadWarehouse(tenantId,destinationWarehouseId,"目的仓库");
WarehouseClient.Detail receiving=loadWarehouse(receivingWarehouseId,"收货仓库");
requireWarehouseType(receiving,"DOMESTIC","收货仓库");
if ("PRIVATE".equals(destinationType)) {
if (destinationWarehouseId!=null) throw new BizException(ResultCode.VALIDATION_FAILED,"私人地址不能引用公共仓库");
} else {
if (destinationWarehouseId==null) throw new BizException(ResultCode.NOT_FOUND,"目的仓库已停用或不可用");
WarehouseClient.Detail destination=loadWarehouse(destinationWarehouseId,"目的仓库");
requireWarehouseType(destination,destinationType,"目的仓库");
}
} catch (FeignException exception) {
throw downstreamFailure(exception);
} catch (BizException exception) {
@@ -82,18 +101,18 @@ public class OrderMasterDataGuard {
if (!StringUtils.hasText(value.partnerName())) throw unavailable("往来单位");
return value;
}
private WarehouseClient.Detail loadWarehouse(long tenantId,long id,String name) {
private WarehouseClient.Detail loadWarehouse(long id,String name) {
ApiResponse<WarehouseClient.Detail> response;
try {
response=warehouses.active(token,tenantId,id);
response=warehouses.active(token,publicTenantId,id);
} catch (FeignException.NotFound exception) {
throw new BizException(ResultCode.NOT_FOUND,"\u6536\u8d27\u4ed3\u5e93\u4e0d\u5b58\u5728\u6216\u5df2\u505c\u7528");
}
requireSuccessful(response,name);
if (response.data()==null || response.data().warehouse()==null) throw unavailable(name);
var value=response.data();
if (!Long.valueOf(tenantId).equals(value.warehouse().tenantId()))
throw new BizException(ResultCode.FORBIDDEN,name+"不属于当前企业");
if (!Long.valueOf(publicTenantId).equals(value.warehouse().tenantId()))
throw new BizException(ResultCode.FORBIDDEN,name+"不属于公共仓库配置");
if (!"ACTIVE".equals(value.warehouse().status()))
throw new BizException(ResultCode.CONFLICT,name+"已停用");
if (!Long.valueOf(id).equals(value.warehouse().id()) || !StringUtils.hasText(value.warehouse().warehouseName())) {
@@ -101,6 +120,11 @@ public class OrderMasterDataGuard {
}
return value;
}
private void requireWarehouseType(WarehouseClient.Detail detail, String expected, String name) {
if (detail == null || detail.warehouse() == null || !expected.equals(detail.warehouse().warehouseType())) {
throw new BizException(ResultCode.VALIDATION_FAILED,name+"类型必须为 "+expected);
}
}
private BizException unavailable(String name) {
return new BizException(ResultCode.SERVICE_UNAVAILABLE,name+"服务暂时不可用");
}