打印箱唛修改 尾程垮桥事件提交
This commit is contained in:
@@ -17,6 +17,15 @@ public interface FirstlegInboundClient {
|
||||
ApiResponse<Long> create(@RequestHeader("X-Internal-Service-Token") String token,
|
||||
@RequestBody OrderApprovedInboundCommand command);
|
||||
|
||||
@PostMapping("/order-preparing")
|
||||
ApiResponse<Long> prepare(@RequestHeader("X-Internal-Service-Token") String token,
|
||||
@RequestBody OrderApprovedInboundCommand command);
|
||||
|
||||
@PostMapping("/order-preparing/batch")
|
||||
ApiResponse<List<InboundReference>> prepareBatch(
|
||||
@RequestHeader("X-Internal-Service-Token") String token,
|
||||
@RequestBody List<OrderApprovedInboundCommand> commands);
|
||||
|
||||
@PostMapping("/order-references")
|
||||
ApiResponse<List<InboundReference>> references(
|
||||
@RequestHeader("X-Internal-Service-Token") String token,
|
||||
|
||||
@@ -8,6 +8,8 @@ import com.baiyue.common.core.api.ResultCode;
|
||||
import com.baiyue.common.core.exception.BizException;
|
||||
import com.baiyue.order.entity.OrderCargoEntity;
|
||||
import com.baiyue.order.repository.OrderRepository;
|
||||
import com.baiyue.order.service.OrderApplicationService;
|
||||
import com.baiyue.order.client.FirstlegInboundClient;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.PathVariable;
|
||||
@@ -68,6 +70,25 @@ public class InternalOrderCargoController {
|
||||
.toList());
|
||||
}
|
||||
|
||||
@GetMapping("/{tenantId}/{orderId}/inbound-snapshot")
|
||||
public ApiResponse<FirstlegInboundClient.OrderApprovedInboundCommand> inboundSnapshot(
|
||||
@RequestHeader(value = "X-Internal-Service-Token", required = false) String token,
|
||||
@PathVariable long tenantId,
|
||||
@PathVariable long orderId) {
|
||||
requireToken(token);
|
||||
if (tenantId <= 0 || orderId <= 0) {
|
||||
throw new BizException(ResultCode.BAD_REQUEST, "租户和订单ID必须大于0");
|
||||
}
|
||||
var order = orders.findOwned(tenantId, orderId);
|
||||
if (order == null) {
|
||||
throw new BizException(ResultCode.NOT_FOUND, "订单不存在或不属于当前客户");
|
||||
}
|
||||
int packageCount = orders.findCargoInheritedByOrder(tenantId, orderId).stream()
|
||||
.map(OrderCargoEntity::getPackageCount).filter(java.util.Objects::nonNull)
|
||||
.mapToInt(Integer::intValue).sum();
|
||||
return ApiResponse.success(OrderApplicationService.inboundCommand(order, packageCount));
|
||||
}
|
||||
|
||||
private void requireToken(String token) {
|
||||
if (token == null || !MessageDigest.isEqual(expectedToken, token.getBytes(StandardCharsets.UTF_8))) {
|
||||
throw new BizException(ResultCode.FORBIDDEN, "内部服务凭证无效");
|
||||
|
||||
@@ -12,6 +12,7 @@ public record MerchantInboundOrderRow(
|
||||
String orderNo,
|
||||
Integer packageCount,
|
||||
BigDecimal weightKg,
|
||||
Long inboundId,
|
||||
String inboundCode,
|
||||
String channelName,
|
||||
String destinationType,
|
||||
@@ -36,12 +37,16 @@ public record MerchantInboundOrderRow(
|
||||
Long operatorId,
|
||||
String operatorName,
|
||||
String remark,
|
||||
String destinationWarehouseName,
|
||||
String expressCompany,
|
||||
String skuNos,
|
||||
String shipmentId,
|
||||
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) {
|
||||
String currency, String skuNo, String model, String material, String productUsage, String brand) {
|
||||
}
|
||||
}
|
||||
|
||||
@@ -46,11 +46,21 @@ public class MerchantInboundOrderListService {
|
||||
.stream().collect(Collectors.toMap(
|
||||
OrderStatusHistoryEntity::getOrderId, Function.identity(), (latest, ignored) -> latest));
|
||||
Map<Long, FirstlegInboundClient.InboundReference> inboundReferences = references(tenantId, orderIds);
|
||||
Map<Long, FirstlegInboundClient.InboundReference> initialReferences = inboundReferences;
|
||||
List<OrderEntity> missing = source.records().stream()
|
||||
.filter(order -> !initialReferences.containsKey(order.getId()))
|
||||
.filter(order -> order.getStatus() == com.baiyue.order.entity.OrderStatus.DRAFT
|
||||
|| order.getStatus() == com.baiyue.order.entity.OrderStatus.SUBMITTED)
|
||||
.toList();
|
||||
if (!missing.isEmpty()) {
|
||||
inboundReferences = repairedReferences(tenantId, inboundReferences, missing, cargoes);
|
||||
}
|
||||
Map<Long, FirstlegInboundClient.InboundReference> finalReferences = inboundReferences;
|
||||
|
||||
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())))
|
||||
finalReferences.get(order.getId())))
|
||||
.toList();
|
||||
return new PageResult<>(records, source.page(), source.size(), source.total(), source.pages());
|
||||
}
|
||||
@@ -69,6 +79,26 @@ public class MerchantInboundOrderListService {
|
||||
}
|
||||
}
|
||||
|
||||
private Map<Long, FirstlegInboundClient.InboundReference> repairedReferences(
|
||||
long tenantId, Map<Long, FirstlegInboundClient.InboundReference> current,
|
||||
List<OrderEntity> missing, Map<Long, List<OrderCargoEntity>> cargoes) {
|
||||
try {
|
||||
List<FirstlegInboundClient.OrderApprovedInboundCommand> commands = missing.stream().map(order -> {
|
||||
int packages = cargoes.getOrDefault(order.getId(), List.of()).stream()
|
||||
.map(OrderCargoEntity::getPackageCount).filter(Objects::nonNull)
|
||||
.mapToInt(Integer::intValue).sum();
|
||||
return OrderApplicationService.inboundCommand(order, packages);
|
||||
}).toList();
|
||||
var response = firstleg.prepareBatch(internalToken, commands);
|
||||
if (response == null || !response.successful() || response.data() == null) return current;
|
||||
Map<Long, FirstlegInboundClient.InboundReference> result = new java.util.HashMap<>(current);
|
||||
response.data().forEach(reference -> result.put(reference.orderId(), reference));
|
||||
return result;
|
||||
} catch (RuntimeException ignored) {
|
||||
return current;
|
||||
}
|
||||
}
|
||||
|
||||
private MerchantInboundOrderRow row(
|
||||
OrderEntity order,
|
||||
List<OrderCargoEntity> cargoes,
|
||||
@@ -89,13 +119,15 @@ public class MerchantInboundOrderListService {
|
||||
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.getCurrency(), cargo.getSkuNo(), 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(),
|
||||
inbound == null ? null : inbound.inboundId(),
|
||||
inbound == null || inbound.inboundCode() == null || inbound.inboundCode().isBlank()
|
||||
? order.getInboundCode() : inbound.inboundCode(), order.getChannelName(),
|
||||
order.getDestinationType(), order.getCustomerName(),
|
||||
consignee == null ? null : consignee.getCompanyName(), joined(cargoes, OrderCargoEntity::getModel),
|
||||
order.getStatus(), totalQuantity, grossWeight, netWeight, volume,
|
||||
@@ -106,6 +138,9 @@ public class MerchantInboundOrderListService {
|
||||
order.getExpressTrackingNo(), order.getShipmentId(), order.getReferenceId(),
|
||||
latestHistory == null ? order.getCreatedBy() : latestHistory.getOperatorId(),
|
||||
latestHistory == null ? null : latestHistory.getOperatorName(), order.getCustomerRemark(),
|
||||
order.getDestinationWarehouseName(), order.getExpressCompany(),
|
||||
joined(cargoes, OrderCargoEntity::getSkuNo),
|
||||
order.getShipmentId(),
|
||||
cargoColumns);
|
||||
}
|
||||
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package com.baiyue.order.service;
|
||||
|
||||
import com.baiyue.common.core.api.PageResult;
|
||||
import com.baiyue.common.core.api.ApiResponse;
|
||||
import com.baiyue.common.core.api.ResultCode;
|
||||
import com.baiyue.common.core.exception.BizException;
|
||||
import com.baiyue.order.dto.OrderDetailResponse;
|
||||
@@ -18,6 +19,10 @@ import org.springframework.dao.DuplicateKeyException;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
import org.springframework.util.StringUtils;
|
||||
import org.springframework.beans.factory.ObjectProvider;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.transaction.support.TransactionSynchronization;
|
||||
import org.springframework.transaction.support.TransactionSynchronizationManager;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
@@ -37,6 +42,8 @@ public class OrderApplicationService {
|
||||
@Resource private OrderMasterDataGuard masterDataGuard;
|
||||
@Resource private OrderPricingChannelGuard pricingChannelGuard;
|
||||
@Resource private ProductImageGuard productImageGuard;
|
||||
@Resource private ObjectProvider<FirstlegInboundClient> firstlegProvider;
|
||||
@Value("${baiyue.security.internal-service-token:}") private String internalToken;
|
||||
|
||||
/** 创建草稿时使用数据库唯一键保证请求幂等。 */
|
||||
@Transactional
|
||||
@@ -63,6 +70,7 @@ public class OrderApplicationService {
|
||||
repository.insertOrder(order);
|
||||
saveChildren(tenantId, userId, order.getId(), request);
|
||||
record(tenantId, order.getId(), null, OrderStatus.DRAFT, "CREATE", null, userId, null);
|
||||
prepareDraftInbound(order, request);
|
||||
return order.getId();
|
||||
}
|
||||
|
||||
@@ -104,6 +112,7 @@ public class OrderApplicationService {
|
||||
repository.replaceDraftChildren(tenantId, id);
|
||||
saveChildren(tenantId, userId, id, request);
|
||||
record(tenantId, id, before, order.getStatus(), "UPDATE", null, userId, null);
|
||||
prepareDraftInbound(order, request);
|
||||
}
|
||||
|
||||
@Transactional
|
||||
@@ -482,10 +491,10 @@ public class OrderApplicationService {
|
||||
event.setPublishStatus("PENDING"); event.setRetryCount(0); event.setCreatedAt(LocalDateTime.now());
|
||||
repository.insertOutbox(event);
|
||||
}
|
||||
static FirstlegInboundClient.OrderApprovedInboundCommand inboundCommand(OrderEntity order) {
|
||||
public static FirstlegInboundClient.OrderApprovedInboundCommand inboundCommand(OrderEntity order) {
|
||||
return inboundCommand(order, null);
|
||||
}
|
||||
static FirstlegInboundClient.OrderApprovedInboundCommand inboundCommand(OrderEntity order,
|
||||
public static FirstlegInboundClient.OrderApprovedInboundCommand inboundCommand(OrderEntity order,
|
||||
Integer totalPackageCount) {
|
||||
return new FirstlegInboundClient.OrderApprovedInboundCommand(
|
||||
order.getTenantId(), order.getId(), order.getOrderNo(), order.getInboundCode(),
|
||||
@@ -499,6 +508,28 @@ public class OrderApplicationService {
|
||||
order.getDestinationWarehouseId(), order.getAmazonWarehouseCode(), order.getDestinationWarehouseName(),
|
||||
order.getCustomerRemark(), order.getExpressCompany(), order.getExpressTrackingNo(), totalPackageCount);
|
||||
}
|
||||
private void prepareDraftInbound(OrderEntity order, OrderRequests.SaveRequest request) {
|
||||
FirstlegInboundClient client = firstlegProvider == null ? null : firstlegProvider.getIfAvailable();
|
||||
if (client == null || !StringUtils.hasText(internalToken)) return;
|
||||
int packageCount = request.cargoes().stream().map(OrderRequests.Cargo::packageCount)
|
||||
.filter(java.util.Objects::nonNull).mapToInt(Integer::intValue).sum();
|
||||
FirstlegInboundClient.OrderApprovedInboundCommand command = inboundCommand(order, packageCount);
|
||||
Runnable prepare = () -> {
|
||||
try {
|
||||
ApiResponse<Long> response = client.prepare(internalToken, command);
|
||||
if (response == null || !response.successful() || response.data() == null) return;
|
||||
} catch (RuntimeException ignored) {
|
||||
// Repaired by MerchantInboundOrderListService on the next query.
|
||||
}
|
||||
};
|
||||
if (TransactionSynchronizationManager.isSynchronizationActive()) {
|
||||
TransactionSynchronizationManager.registerSynchronization(new TransactionSynchronization() {
|
||||
@Override public void afterCommit() { prepare.run(); }
|
||||
});
|
||||
} else {
|
||||
prepare.run();
|
||||
}
|
||||
}
|
||||
private int totalPackageCount(OrderEntity order) {
|
||||
long total = repository.findCargo(order.getTenantId(), order.getId()).stream()
|
||||
.map(com.baiyue.order.entity.OrderCargoEntity::getPackageCount)
|
||||
|
||||
@@ -665,6 +665,22 @@ components:
|
||||
properties:
|
||||
orderId: {type: string, pattern: '^[1-9][0-9]*$'}
|
||||
orderNo: {type: string}
|
||||
inboundId: {type: string, pattern: '^[1-9][0-9]*$', nullable: true}
|
||||
inboundCode: {type: string}
|
||||
channelName: {type: string}
|
||||
destinationWarehouseName: {type: string}
|
||||
status: {type: string}
|
||||
packageCount: {type: integer}
|
||||
expressCompany: {type: string}
|
||||
trackingNo: {type: string}
|
||||
skuNos: {type: string, description: 多个 SKU 使用中文顿号分隔}
|
||||
totalGrossWeightKg: {type: number}
|
||||
totalNetWeightKg: {type: number}
|
||||
totalVolumeCbm: {type: number}
|
||||
totalQuantity: {type: integer}
|
||||
remark: {type: string}
|
||||
shipmentId: {type: string}
|
||||
referenceId: {type: string}
|
||||
pricingTaxMode: {$ref: '#/components/schemas/PricingTaxMode'}
|
||||
ContainerSlice:
|
||||
type: object
|
||||
|
||||
Reference in New Issue
Block a user