fix: unify same-carton order metrics
This commit is contained in:
@@ -140,8 +140,10 @@ public class InternalOrderCargoController {
|
||||
// 申报重量/体积必须属于当前订单。拆分子单未物化独立货物事实时不得复制根单整单总量。
|
||||
List<OrderCargoEntity> cargoes = orders.findCargo(tenantId, orderId);
|
||||
return ApiResponse.success(new MeasurementDeclarationSnapshot(
|
||||
order.getReferenceId(), sum(cargoes, OrderCargoEntity::getGrossWeightKg),
|
||||
sum(cargoes, OrderCargoEntity::getVolumeCbm),
|
||||
order.getReferenceId(), OrderCargoPackageCounts.physicalMetric(
|
||||
cargoes, order.getFulfillmentType(), OrderCargoEntity::getGrossWeightKg),
|
||||
OrderCargoPackageCounts.physicalMetric(
|
||||
cargoes, order.getFulfillmentType(), OrderCargoEntity::getVolumeCbm),
|
||||
cargoes.stream().map(OrderCargoEntity::getCargoName).filter(Objects::nonNull)
|
||||
.map(String::trim).filter(value -> !value.isEmpty()).distinct()
|
||||
.collect(Collectors.joining("、"))));
|
||||
|
||||
@@ -229,7 +229,7 @@ public final class OrderRequests {
|
||||
@Schema(description = "Product image file ID / 产品图片文件ID") Long productImageFileId,
|
||||
@Schema(description = "Authoritative wood-product decision frozen with this cargo line / 木制品权威判定,随货物行冻结", requiredMode = Schema.RequiredMode.REQUIRED)
|
||||
@NotNull Boolean woodenProduct,
|
||||
@Schema(description = "Mixed-carton group. Cargo lines with the same value share physical cartons / 混箱组合号;相同组合号的货物行属于同一批物理箱", maxLength = 32)
|
||||
@Schema(description = "Client-generated same-carton key. Lines with the same value share carton count, dimensions, weight and volume / 客户端添加同箱 SKU 时生成;同组物理箱字段只汇总一次", maxLength = 32)
|
||||
@Size(max = 32) String packingGroupNo
|
||||
) {
|
||||
public Cargo(String cargoName, String hsCode, String packageType, int packageCount,
|
||||
|
||||
@@ -107,9 +107,12 @@ public class MerchantInboundOrderListService {
|
||||
int packageCount = OrderCargoPackageCounts.physical(cargoes, order.getFulfillmentType());
|
||||
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 grossWeight = OrderCargoPackageCounts.physicalMetric(
|
||||
cargoes, order.getFulfillmentType(), OrderCargoEntity::getGrossWeightKg);
|
||||
BigDecimal netWeight = OrderCargoPackageCounts.physicalMetric(
|
||||
cargoes, order.getFulfillmentType(), OrderCargoEntity::getNetWeightKg);
|
||||
BigDecimal volume = OrderCargoPackageCounts.physicalMetric(
|
||||
cargoes, order.getFulfillmentType(), OrderCargoEntity::getVolumeCbm);
|
||||
BigDecimal declaredAmount = sum(cargoes, OrderCargoEntity::getDeclaredValue);
|
||||
|
||||
List<MerchantInboundOrderRow.CargoColumn> cargoColumns = cargoes.stream()
|
||||
|
||||
@@ -798,9 +798,12 @@ public class OrderApplicationService {
|
||||
|| !Objects.equals(first.packageType(), cargo.packageType())
|
||||
|| !sameDecimal(first.lengthCm(), cargo.lengthCm())
|
||||
|| !sameDecimal(first.widthCm(), cargo.widthCm())
|
||||
|| !sameDecimal(first.heightCm(), cargo.heightCm()))) {
|
||||
|| !sameDecimal(first.heightCm(), cargo.heightCm())
|
||||
|| !sameDecimal(first.grossWeightKg(), cargo.grossWeightKg())
|
||||
|| !sameDecimal(first.netWeightKg(), cargo.netWeightKg())
|
||||
|| !sameDecimal(first.volumeCbm(), cargo.volumeCbm()))) {
|
||||
throw new BizException(ResultCode.VALIDATION_FAILED,
|
||||
"同一混箱组合的箱数、包装类型和箱规必须一致:" + group);
|
||||
"同箱 SKU 的箱数、包装类型、箱规、重量和体积必须一致");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7,6 +7,8 @@ import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
import java.util.Set;
|
||||
import java.math.BigDecimal;
|
||||
import java.util.function.Function;
|
||||
|
||||
/** Calculates physical cartons without double-counting SKU lines in a mixed-carton group. */
|
||||
public final class OrderCargoPackageCounts {
|
||||
@@ -21,4 +23,15 @@ public final class OrderCargoPackageCounts {
|
||||
return countedGroups.add(group) ? count : 0;
|
||||
}).sum();
|
||||
}
|
||||
|
||||
/** Sums a physical-carton metric once per same-carton group. */
|
||||
public static BigDecimal physicalMetric(List<OrderCargoEntity> cargoes, String fulfillmentType,
|
||||
Function<OrderCargoEntity, BigDecimal> getter) {
|
||||
Set<String> countedGroups = new HashSet<>();
|
||||
List<BigDecimal> values = cargoes.stream().filter(Objects::nonNull).filter(cargo -> {
|
||||
String group = StringUtils.hasText(cargo.getPackingGroupNo()) ? cargo.getPackingGroupNo().trim() : null;
|
||||
return !"ONE_CLICK_DROPSHIP".equals(fulfillmentType) || group == null || countedGroups.add(group);
|
||||
}).map(getter).filter(Objects::nonNull).toList();
|
||||
return values.isEmpty() ? null : values.stream().reduce(BigDecimal.ZERO, BigDecimal::add);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -508,9 +508,12 @@ public class UnifiedOrderQueryService {
|
||||
Integer totalPackageCount = hasPackageCount
|
||||
? OrderCargoPackageCounts.physical(cargoes, fulfillmentType)
|
||||
: null;
|
||||
BigDecimal grossWeightKg = sum(cargoes, OrderCargoEntity::getGrossWeightKg);
|
||||
BigDecimal netWeightKg = sum(cargoes, OrderCargoEntity::getNetWeightKg);
|
||||
BigDecimal volumeCbm = sum(cargoes, OrderCargoEntity::getVolumeCbm);
|
||||
BigDecimal grossWeightKg = OrderCargoPackageCounts.physicalMetric(
|
||||
cargoes, fulfillmentType, OrderCargoEntity::getGrossWeightKg);
|
||||
BigDecimal netWeightKg = OrderCargoPackageCounts.physicalMetric(
|
||||
cargoes, fulfillmentType, OrderCargoEntity::getNetWeightKg);
|
||||
BigDecimal volumeCbm = OrderCargoPackageCounts.physicalMetric(
|
||||
cargoes, fulfillmentType, OrderCargoEntity::getVolumeCbm);
|
||||
return new CargoSummary(skuNos, shipmentIds, referenceIds, totalQuantity, totalPackageCount,
|
||||
grossWeightKg, netWeightKg, volumeCbm);
|
||||
}
|
||||
@@ -520,6 +523,7 @@ public class UnifiedOrderQueryService {
|
||||
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) {
|
||||
if (status == null) return null;
|
||||
|
||||
@@ -1262,7 +1262,7 @@ components:
|
||||
heightCm: {type: number, minimum: 0, description: 箱规高(厘米)}
|
||||
unitsPerPackage: {type: integer, minimum: 1, description: 每箱数量;提交时必填}
|
||||
packageCount: {type: integer, minimum: 1, description: 箱数}
|
||||
packingGroupNo: {type: string, maxLength: 32, description: 一件代发混箱组合号;相同组合号的货物行共享同一批物理箱,组内箱数、包装类型和箱规必须一致}
|
||||
packingGroupNo: {type: string, maxLength: 32, description: 一件代发同箱关联键,由客户端在添加同箱 SKU 时生成;同组货物行共享物理箱,箱数、包装类型、箱规、重量和体积必须一致且汇总时只计算一次}
|
||||
grossWeightKg: {type: number, exclusiveMinimum: true, minimum: 0, description: 总毛重}
|
||||
volumeCbm: {type: number, exclusiveMinimum: true, minimum: 0, description: 总体积}
|
||||
totalQuantity: {type: integer, minimum: 1, description: 总数量;提交时必填且必须等于每箱数量 × 箱数}
|
||||
|
||||
Reference in New Issue
Block a user