fix: complete order measurement downstream flow

This commit is contained in:
2026-09-18 14:58:40 +08:00
parent 02d2474141
commit c8a99f9fff
43 changed files with 621 additions and 52 deletions
@@ -16,7 +16,9 @@ public final class DeliveryResponses {
List<TransferDelivery> deliveries, boolean replayed) {}
public record OutboundRow(Long id, String outboundNo, String dispatchNo, String overseasWarehouseId, String lxCodes,
String status, int palletCount, int packageCount, LocalDateTime createdAt, String outboundType) {}
String status, int palletCount, int packageCount, BigDecimal grossWeightKg,
BigDecimal volumeWeightKg, BigDecimal volumeCbm,
LocalDateTime createdAt, String outboundType) {}
public record DeliveryRow(Long id, String customerId, String customerName, String deliveryNo,
String outboundNo, String dispatchNo, String overseasWarehouseId,
@@ -51,7 +53,9 @@ public final class DeliveryResponses {
/** palletNo is the warehouse-authoritative physical pallet code after inbound assignment. */
public record OutboundPalletRow(Long id, String palletNo, String cartonMarks, String inboundCode,
String destinationWarehouseCode, String destinationWarehouseName,
String skuCode, int packageCount, int pickedPackageCount, String status) {}
String skuCode, int packageCount, BigDecimal grossWeightKg,
BigDecimal volumeWeightKg, BigDecimal volumeCbm,
int pickedPackageCount, String status) {}
public record OutboundDetail(OutboundRow outbound, List<DeliveryRow> deliveries, List<OutboundPalletRow> pallets) {}
public record OneClickCandidate(Long inventoryPositionId, String orderNo, String customerId, String customerName, String overseasWarehouseId,
String overseasWarehouseName, String palletNo, String inboundCode,
@@ -5,6 +5,7 @@ import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Data;
import java.math.BigDecimal;
import java.time.LocalDateTime;
/** Outbound document created when a dispatch is transferred to delivery. */
@@ -24,6 +25,9 @@ public class OutboundOrder {
private String status;
private Integer packageCount;
private Integer palletCount;
private BigDecimal grossWeightKg;
private BigDecimal volumeWeightKg;
private BigDecimal volumeCbm;
private String idempotencyKey;
private String requestHash;
private String createdBy;
@@ -5,6 +5,7 @@ import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Data;
import java.math.BigDecimal;
import java.time.LocalDateTime;
/** Pallet-level immutable snapshot belonging to one outbound document. */
@@ -21,6 +22,9 @@ public class OutboundPalletItem {
private String destinationWarehouseCode;
private String destinationWarehouseName;
private Integer packageCount;
private BigDecimal grossWeightKg;
private BigDecimal volumeWeightKg;
private BigDecimal volumeCbm;
private Integer pickedPackageCount;
private String status;
private String skuCode;
@@ -165,7 +165,11 @@ public class DeliveryTransferService {
outbound.setOverseasWarehouseId(dispatch.getOverseasWarehouseId()); outbound.setStatus("WAIT_OUTBOUND"); outbound.setOutboundType("DISPATCH_DELIVERY");
outbound.setLxCodes(resolveLxCodes(customerId, items));
outbound.setPackageCount(items.stream().map(DispatchItem::getPackageCount).filter(Objects::nonNull).mapToInt(Integer::intValue).sum());
outbound.setPalletCount(items.size()); outbound.setIdempotencyKey(request.idempotencyKey().trim());
outbound.setPalletCount(items.size());
outbound.setGrossWeightKg(sum(items, DispatchItem::getGrossWeightKg));
outbound.setVolumeWeightKg(sum(items, DispatchItem::getVolumeWeightKg));
outbound.setVolumeCbm(sum(items, DispatchItem::getVolumeCbm));
outbound.setIdempotencyKey(request.idempotencyKey().trim());
outbound.setCreatedBy(operatorId); outbound.setCreatedAt(now); outbound.setUpdatedAt(now);
try {
outboundOrders.insert(outbound);
@@ -190,7 +194,9 @@ public class DeliveryTransferService {
item.setDestinationWarehouseId(source.getDestinationWarehouseId());
item.setDestinationWarehouseCode(source.getDestinationWarehouseCode());
item.setDestinationWarehouseName(source.getDestinationWarehouseName());
item.setPackageCount(Objects.requireNonNullElse(source.getPackageCount(), 0)); item.setPickedPackageCount(0); item.setStatus("WAIT_PICK");
item.setPackageCount(Objects.requireNonNullElse(source.getPackageCount(), 0));
item.setGrossWeightKg(source.getGrossWeightKg()); item.setVolumeWeightKg(source.getVolumeWeightKg());
item.setVolumeCbm(source.getVolumeCbm()); item.setPickedPackageCount(0); item.setStatus("WAIT_PICK");
if (StringUtils.hasText(source.getCartonMarks())) {
item.setCartonMarks(source.getCartonMarks());
} else if (source.getWarehousePalletId() != null) {
@@ -236,8 +242,8 @@ public class DeliveryTransferService {
delivery.setSellerName(trim(request.sellerName())); delivery.setPlannedDeliveryAt(request.plannedDeliveryAt());
delivery.setPackageCount(groupItems.stream().map(DispatchItem::getPackageCount).filter(Objects::nonNull).mapToInt(Integer::intValue).sum());
delivery.setPalletCount(groupItems.size());
delivery.setTotalVolumeCbm(groupItems.stream().map(DispatchItem::getVolumeCbm).filter(Objects::nonNull).reduce(BigDecimal.ZERO, BigDecimal::add));
delivery.setTotalWeightKg(totalWeight(customerId, groupItems)); delivery.setExpectedArrivalAt(dispatch.getEstimatedArrivalAt()); delivery.setRemark(trim(request.remark()));
delivery.setTotalVolumeCbm(sum(groupItems, DispatchItem::getVolumeCbm));
delivery.setTotalWeightKg(sum(groupItems, DispatchItem::getGrossWeightKg)); delivery.setExpectedArrivalAt(dispatch.getEstimatedArrivalAt()); delivery.setRemark(trim(request.remark()));
delivery.setIdempotencyKey(childKey(request.idempotencyKey(), "DEST-" + groupIndex++)); delivery.setCreatedBy(operatorId);
delivery.setCreatedAt(now); delivery.setUpdatedAt(now); deliveryOrders.insert(delivery);
recordOperation(customerId, delivery.getId(), operatorId, "CREATE_DELIVERY", "按目的FBA仓生成派送单", now);
@@ -1171,11 +1177,12 @@ public class DeliveryTransferService {
d.getDeliveryNo(), d.getStatus(), d.getDestinationWarehouseId(), d.getDestinationWarehouseCode(),
d.getDestinationWarehouseName(), value(d.getPalletCount()), value(d.getPackageCount()))).toList(), replayed);
}
private DeliveryResponses.OutboundRow outboundRow(OutboundOrder o) { return new DeliveryResponses.OutboundRow(o.getId(), o.getOutboundNo(), o.getDispatchNo(), o.getOverseasWarehouseId(), o.getLxCodes(), o.getStatus(), o.getPalletCount(), o.getPackageCount(), o.getCreatedAt(), o.getOutboundType()); }
private DeliveryResponses.OutboundRow outboundRow(OutboundOrder o) { return new DeliveryResponses.OutboundRow(o.getId(), o.getOutboundNo(), o.getDispatchNo(), o.getOverseasWarehouseId(), o.getLxCodes(), o.getStatus(), o.getPalletCount(), o.getPackageCount(), o.getGrossWeightKg(), o.getVolumeWeightKg(), o.getVolumeCbm(), o.getCreatedAt(), o.getOutboundType()); }
private DeliveryResponses.OutboundPalletRow outboundPalletRow(OutboundPalletItem item) {
return new DeliveryResponses.OutboundPalletRow(item.getId(), item.getPalletNo(), item.getCartonMarks(),
item.getInboundCode(), item.getDestinationWarehouseCode(), item.getDestinationWarehouseName(),
item.getSkuCode(), value(item.getPackageCount()), value(item.getPickedPackageCount()), item.getStatus());
item.getSkuCode(), value(item.getPackageCount()), item.getGrossWeightKg(), item.getVolumeWeightKg(),
item.getVolumeCbm(), value(item.getPickedPackageCount()), item.getStatus());
}
private DeliveryResponses.OneClickCandidate oneClickCandidate(DropshipOutboundCandidate candidate) {
return new DeliveryResponses.OneClickCandidate(candidate.getInventoryPositionId(), candidate.getOrderNo(), candidate.getCustomerId(), candidate.getCustomerName(),
@@ -1235,26 +1242,9 @@ public class DeliveryTransferService {
Math.addExact(quantity, other.quantity));
}
}
private BigDecimal totalWeight(String customerId, List<DispatchItem> items) {
List<Long> palletIds = items.stream().map(DispatchItem::getWarehousePalletId)
.filter(Objects::nonNull).distinct().toList();
List<WarehouseTransferPallet> transferPallets = palletIds.isEmpty() ? List.of()
: warehouseTransferPallets.selectList(new LambdaQueryWrapper<WarehouseTransferPallet>()
.eq(WarehouseTransferPallet::getCustomerId, customerId)
.in(WarehouseTransferPallet::getWarehousePalletId, palletIds));
Set<Long> measuredPalletIds = transferPallets.stream()
.map(WarehouseTransferPallet::getWarehousePalletId).collect(java.util.stream.Collectors.toSet());
BigDecimal measuredWeight = transferPallets.stream().map(WarehouseTransferPallet::getGrossWeightKg)
.filter(Objects::nonNull).reduce(BigDecimal.ZERO, BigDecimal::add);
List<Long> orderIds = items.stream()
.filter(item -> item.getWarehousePalletId() == null || !measuredPalletIds.contains(item.getWarehousePalletId()))
.map(DispatchItem::getOrderId).filter(Objects::nonNull).distinct().toList();
if (orderIds.isEmpty()) return measuredWeight;
BigDecimal orderWeight = tailOrderDetails.selectList(new LambdaQueryWrapper<LastlegOrderDetail>()
.eq(LastlegOrderDetail::getCustomerId, customerId).in(LastlegOrderDetail::getOrderId, orderIds))
.stream().map(LastlegOrderDetail::getGrossWeightKg).filter(Objects::nonNull)
.reduce(BigDecimal.ZERO, BigDecimal::add);
return measuredWeight.add(orderWeight);
private static BigDecimal sum(List<DispatchItem> items,
java.util.function.Function<DispatchItem, BigDecimal> getter) {
return items.stream().map(getter).filter(Objects::nonNull).reduce(BigDecimal.ZERO, BigDecimal::add);
}
private static String trim(String value) { return StringUtils.hasText(value) ? value.trim() : null; }
private String hash(Object value) {
@@ -17,6 +17,7 @@ public record DispatchResponse(Long id, String dispatchNo, String vehiclePlate,
String overseasWarehouseId, String overseasWarehouseName,
String orderNo, String orderRefs, String inboundCode, String destinationWarehouseCode,
String destinationWarehouseName, String fbaWarehouseCode, int packageCount,
BigDecimal grossWeightKg, BigDecimal volumeWeightKg,
BigDecimal volumeCbm, String sourceStage) {
}
@@ -36,6 +36,8 @@ public class DispatchItem {
private String contactName;
private String contactPhone;
private Integer packageCount;
private BigDecimal grossWeightKg;
private BigDecimal volumeWeightKg;
private BigDecimal volumeCbm;
/** PLAN for planned pallets; RECEIVED for warehouse/entity pallets. */
private String sourceStage;
@@ -410,6 +410,8 @@ public class DispatchService {
item.setContactName(candidate.contactName());
item.setContactPhone(candidate.contactPhone());
item.setPackageCount(Objects.requireNonNullElse(candidate.packageCount(), 0));
item.setGrossWeightKg(Objects.requireNonNullElse(candidate.grossWeightKg(), BigDecimal.ZERO));
item.setVolumeWeightKg(Objects.requireNonNullElse(candidate.volumeWeightKg(), BigDecimal.ZERO));
item.setVolumeCbm(Objects.requireNonNullElse(candidate.volumeCbm(), BigDecimal.ZERO));
item.setSourceStage(candidate.sourceStage());
item.setCartonMarks(mergeCartonMarks(candidate.cartonMarks(), candidate.relabelCartonMarks()));
@@ -457,7 +459,7 @@ public class DispatchService {
DispatchOrder dispatch = new DispatchOrder(); dispatch.setId(IdWorker.getId()); dispatch.setCustomerId(customerId);
dispatch.setDispatchNo(orderNoGenerator.next("DISPATCH", warehouse, dispatch.getId())); dispatch.setOverseasWarehouseId(warehouse); dispatch.setOverseasWarehouseName(selected.get(0).overseasWarehouseName());
dispatch.setRoute(candidateRoute(selected)); dispatch.setFbaAppointmentNo(trimToNull(request.fbaAppointmentNo())); dispatch.setFbaAppointmentStatus(defaultStatus(request.fbaAppointmentStatus())); dispatch.setVehicleAppointmentStatus(defaultStatus(request.vehicleAppointmentStatus())); dispatch.setStatus(PENDING_DEPARTURE); dispatch.setItemCount(selected.size()); dispatch.setPalletCount(selected.size()); dispatch.setPackageCount(selected.stream().map(DispatchPalletCandidate::packageCount).filter(Objects::nonNull).mapToInt(Integer::intValue).sum()); dispatch.setPickedPackageCount(0); dispatch.setShippedPackageCount(0); dispatch.setCreatedBy(trimToNull(operatorId)); dispatch.setCreatedAt(now); dispatch.setUpdatedAt(now); orders.insert(dispatch);
for (DispatchPalletCandidate candidate : selected) { DispatchItem item = new DispatchItem(); item.setId(IdWorker.getId()); item.setDispatchOrderId(dispatch.getId()); item.setCustomerId(customerId); item.setWarehousePalletId(candidate.warehousePalletId()); item.setOrderId(candidate.orderId()); item.setOverseasWarehouseId(candidate.overseasWarehouseId()); item.setOverseasWarehouseName(candidate.overseasWarehouseName()); item.setOrderNo(candidate.orderNo()); item.setOrderRefs(candidate.orderRefs()); item.setInboundCode(candidate.inboundCode()); item.setPalletNo(candidate.palletNo()); item.setDestinationWarehouseCode(candidate.destinationWarehouseCode()); item.setDestinationWarehouseName(candidate.destinationWarehouseName()); item.setFbaWarehouseCode(candidate.fbaWarehouseCode()); item.setPackageCount(Objects.requireNonNullElse(candidate.packageCount(), 0)); item.setVolumeCbm(Objects.requireNonNullElse(candidate.volumeCbm(), BigDecimal.ZERO)); item.setSourceStage("RELABEL"); item.setCartonMarks(candidate.relabelCartonMarks()); item.setSourceBusinessType("RELABEL_ORDER"); item.setSourceBusinessNo(request.relabelNo()); item.setCreatedAt(now); items.insert(item); }
for (DispatchPalletCandidate candidate : selected) { DispatchItem item = new DispatchItem(); item.setId(IdWorker.getId()); item.setDispatchOrderId(dispatch.getId()); item.setCustomerId(customerId); item.setWarehousePalletId(candidate.warehousePalletId()); item.setOrderId(candidate.orderId()); item.setOverseasWarehouseId(candidate.overseasWarehouseId()); item.setOverseasWarehouseName(candidate.overseasWarehouseName()); item.setOrderNo(candidate.orderNo()); item.setOrderRefs(candidate.orderRefs()); item.setInboundCode(candidate.inboundCode()); item.setPalletNo(candidate.palletNo()); item.setDestinationWarehouseCode(candidate.destinationWarehouseCode()); item.setDestinationWarehouseName(candidate.destinationWarehouseName()); item.setFbaWarehouseCode(candidate.fbaWarehouseCode()); item.setPackageCount(Objects.requireNonNullElse(candidate.packageCount(), 0)); item.setGrossWeightKg(Objects.requireNonNullElse(candidate.grossWeightKg(), BigDecimal.ZERO)); item.setVolumeWeightKg(Objects.requireNonNullElse(candidate.volumeWeightKg(), BigDecimal.ZERO)); item.setVolumeCbm(Objects.requireNonNullElse(candidate.volumeCbm(), BigDecimal.ZERO)); item.setSourceStage("RELABEL"); item.setCartonMarks(candidate.relabelCartonMarks()); item.setSourceBusinessType("RELABEL_ORDER"); item.setSourceBusinessNo(request.relabelNo()); item.setCreatedAt(now); items.insert(item); }
DispatchPdaTask task = new DispatchPdaTask(); task.setId(IdWorker.getId()); task.setCustomerId(customerId); task.setDispatchOrderId(dispatch.getId()); task.setTaskNo("DPDA" + task.getId()); task.setStatus("PDA_PENDING"); task.setWarehouseId(warehouse); task.setPushedAt(now); task.setCreatedAt(now); task.setUpdatedAt(now); pdaTasks.insert(task);
if (candidates.markRelabelPreDispatched(customerId, request.relabelNo()) != 1) throw new ResponseStatusException(HttpStatus.CONFLICT, "换标订单已被其他排车占用");
return response(dispatch, items.findByDispatchOrder(customerId, dispatch.getId()));
@@ -653,7 +655,8 @@ public class DispatchService {
item.getWarehousePalletId(), item.getPalletNo(), item.getOverseasWarehouseId(), item.getOverseasWarehouseName(),
item.getOrderNo(), item.getOrderRefs(), item.getInboundCode(),
item.getDestinationWarehouseCode(), item.getDestinationWarehouseName(), item.getFbaWarehouseCode(),
Objects.requireNonNullElse(item.getPackageCount(), 0), item.getVolumeCbm(), item.getSourceStage())).toList(),
Objects.requireNonNullElse(item.getPackageCount(), 0), item.getGrossWeightKg(),
item.getVolumeWeightKg(), item.getVolumeCbm(), item.getSourceStage())).toList(),
bolLineList == null ? List.of() : bolLineList);
}
@@ -47,6 +47,10 @@ public record LastlegOrderSummary(
Integer receivedPackageCount,
@Schema(description = "实收减预报箱数;尚未完成收货时为空")
Integer packageDifference,
@Schema(description = "头程冻结货物毛重(千克)")
BigDecimal grossWeightKg,
@Schema(description = "头程冻结货物净重(千克)")
BigDecimal netWeightKg,
BigDecimal volumeCbm,
Integer productQuantity,
BigDecimal volumeWeightKg,
@@ -22,6 +22,8 @@ public record InboundPlanListResponse(
String customerName,
Integer packageCount,
Integer pickedPackageCount,
BigDecimal grossWeightKg,
BigDecimal netWeightKg,
BigDecimal volumeCbm,
Integer palletCount,
boolean assigned,
@@ -39,7 +41,8 @@ public record InboundPlanListResponse(
public InboundPlanListResponse withReceivingWarehouse(String warehouseCode, String warehouseName) {
return new InboundPlanListResponse(lineId, planId, planNo, customerId, orderId, inboundCode, lxCode,
orderType, overseasWarehouseId, warehouseCode, warehouseName, warehouseId, this.warehouseCode,
this.warehouseName, fbaWarehouseCode, customerName, packageCount, pickedPackageCount, volumeCbm,
this.warehouseName, fbaWarehouseCode, customerName, packageCount, pickedPackageCount,
grossWeightKg, netWeightKg, volumeCbm,
palletCount, assigned, mergeAllowed, urgent, status, appointmentNo, appointmentStatus, appointmentAt,
expectedLoadingAt, dispatchStatus, createdAt, version);
}
@@ -19,6 +19,8 @@ public record InboundPlanResponse(
String status,
int lineCount,
int palletCount,
BigDecimal totalGrossWeightKg,
BigDecimal totalNetWeightKg,
BigDecimal totalVolumeCbm,
int expectedPackageCount,
int pickedPackageCount,
@@ -38,7 +40,8 @@ public record InboundPlanResponse(
) {
public record Line(Long id, Long orderId, String inboundCode, String fbaWarehouseCode, String destinationWarehouseId,
String destinationWarehouseCode, String destinationWarehouseName,
BigDecimal volumeCbm, int requiredPackageCount, int plannedPalletCount) {
BigDecimal grossWeightKg, BigDecimal netWeightKg, BigDecimal volumeCbm,
int requiredPackageCount, int plannedPalletCount) {
}
public record Pallet(Long id, String palletNo, String destinationWarehouseId,
@@ -17,6 +17,8 @@ public interface InboundPlanOrderMapper {
record ReceivingWarehouseSnapshot(String overseasWarehouseId, String overseasWarehouseCode,
String overseasWarehouseName) { }
record DetailOrderSnapshot(String orderNo, String customerName, String orderType) { }
record OrderWeightSnapshot(Long orderId, java.math.BigDecimal grossWeightKg,
java.math.BigDecimal netWeightKg) { }
record ContainerWarehouseRef(String customerId, Long orderId, String sourceContainerBookingId,
String overseasWarehouseId) { }
record ContainerPreviewOrderRow(
@@ -116,6 +118,17 @@ public interface InboundPlanOrderMapper {
DetailOrderSnapshot findDetailOrder(@Param("customerId") String customerId,
@Param("orderId") Long orderId);
@Select("<script>SELECT o.id AS orderId," +
"COALESCE(SUM(d.gross_weight_kg),MAX(i.gross_weight_kg),0) AS grossWeightKg," +
"COALESCE(SUM(d.net_weight_kg),MAX(i.net_weight_kg),0) AS netWeightKg " +
"FROM ll_order o LEFT JOIN ll_order_detail d ON d.order_id=o.id AND d.customer_id=o.customer_id " +
"LEFT JOIN ll_inbound_order i ON i.id=o.id AND i.customer_id=o.customer_id " +
"WHERE o.customer_id=#{customerId} AND o.id IN " +
"<foreach collection='orderIds' item='id' open='(' separator=',' close=')'>#{id}</foreach> " +
"GROUP BY o.id</script>")
List<OrderWeightSnapshot> findOrderWeights(@Param("customerId") String customerId,
@Param("orderIds") List<Long> orderIds);
@Update("UPDATE ll_order SET inbound_order_no=#{planNo},current_status='INBOUND_PLANNED'," +
"pallet_merge_flag='MERGED',pallet_count=#{palletCount},updated_at=#{updatedAt} " +
"WHERE customer_id=#{customerId} AND id=#{orderId}")
@@ -43,6 +43,10 @@ public interface InboundPlanQueryMapper {
"l.destination_warehouse_name warehouseName,l.fba_warehouse_code fbaWarehouseCode," +
"o.customer_name customerName,l.required_package_count packageCount," +
"COALESCE((SELECT SUM(pa.picked_package_count) FROM ll_inbound_plan_pallet_allocation pa WHERE pa.line_id=l.id),0) pickedPackageCount," +
"COALESCE((SELECT SUM(d.gross_weight_kg) FROM ll_order_detail d WHERE d.order_id=l.order_id AND d.customer_id=p.customer_id)," +
"(SELECT i.gross_weight_kg FROM ll_inbound_order i WHERE i.id=l.order_id AND i.customer_id=p.customer_id),0) grossWeightKg," +
"COALESCE((SELECT SUM(d.net_weight_kg) FROM ll_order_detail d WHERE d.order_id=l.order_id AND d.customer_id=p.customer_id)," +
"(SELECT i.net_weight_kg FROM ll_inbound_order i WHERE i.id=l.order_id AND i.customer_id=p.customer_id),0) netWeightKg," +
"l.volume_cbm volumeCbm," +
"l.planned_pallet_count palletCount,p.assigned_flag assigned,p.merge_required mergeAllowed," +
"p.urgent_flag urgent,p.status status,a.appointment_no appointmentNo," +
@@ -1077,6 +1077,16 @@ public class InboundPlanService {
}
List<InboundPlanLine> lines = lineMapper.selectList(new LambdaQueryWrapper<InboundPlanLine>()
.eq(InboundPlanLine::getPlanId, plan.getId()).orderByAsc(InboundPlanLine::getId));
Map<Long, InboundPlanOrderMapper.OrderWeightSnapshot> weights = lines.isEmpty() ? Map.of()
: orderMapper.findOrderWeights(plan.getCustomerId(), lines.stream().map(InboundPlanLine::getOrderId)
.filter(Objects::nonNull).distinct().toList()).stream()
.collect(Collectors.toMap(InboundPlanOrderMapper.OrderWeightSnapshot::orderId, value -> value));
BigDecimal totalGrossWeightKg = weights.values().stream()
.map(InboundPlanOrderMapper.OrderWeightSnapshot::grossWeightKg).filter(Objects::nonNull)
.reduce(BigDecimal.ZERO, BigDecimal::add);
BigDecimal totalNetWeightKg = weights.values().stream()
.map(InboundPlanOrderMapper.OrderWeightSnapshot::netWeightKg).filter(Objects::nonNull)
.reduce(BigDecimal.ZERO, BigDecimal::add);
List<InboundPlanPallet> pallets = palletMapper.selectList(new LambdaQueryWrapper<InboundPlanPallet>()
.eq(InboundPlanPallet::getPlanId, plan.getId()).orderByAsc(InboundPlanPallet::getSequenceNo));
List<InboundPlanPalletAllocation> allocations = allocationMapper.selectList(
@@ -1116,11 +1126,14 @@ public class InboundPlanService {
sourceOrder == null ? null : sourceOrder.customerName(),
sourceOrder == null ? null : sourceOrder.orderType(), plan.getContainerNo(),
authoritativeWarehouse.warehouseCode(), authoritativeWarehouse.warehouseName(),
plan.getStatus(), plan.getLineCount(), plan.getPalletCount(), plan.getTotalVolumeCbm(),
plan.getStatus(), plan.getLineCount(), plan.getPalletCount(), totalGrossWeightKg,
totalNetWeightKg, plan.getTotalVolumeCbm(),
lines.stream().mapToInt(InboundPlanLine::getRequiredPackageCount).sum(),
allocations.stream().mapToInt(InboundPlanPalletAllocation::getPickedPackageCount).sum(),
lines.stream().map(line -> new InboundPlanResponse.Line(line.getId(), line.getOrderId(), line.getInboundCode(), line.getFbaWarehouseCode(),
line.getDestinationWarehouseId(), line.getDestinationWarehouseCode(), line.getDestinationWarehouseName(),
weights.containsKey(line.getOrderId()) ? weights.get(line.getOrderId()).grossWeightKg() : BigDecimal.ZERO,
weights.containsKey(line.getOrderId()) ? weights.get(line.getOrderId()).netWeightKg() : BigDecimal.ZERO,
line.getVolumeCbm(), line.getRequiredPackageCount(), line.getPlannedPalletCount())).toList(),
pallets.stream().map(pallet -> new InboundPlanResponse.Pallet(pallet.getId(), pallet.getPalletNo(),
pallet.getDestinationWarehouseId(), pallet.getDestinationWarehouseCode(), pallet.getDestinationWarehouseName(),
@@ -12,6 +12,7 @@ import org.apache.ibatis.annotations.Select;
import org.apache.ibatis.annotations.Update;
import java.util.List;
import java.math.BigDecimal;
@Mapper
public interface LastlegOrderMapper extends BaseMapper<LastlegOrder> {
@@ -27,6 +28,17 @@ public interface LastlegOrderMapper extends BaseMapper<LastlegOrder> {
record DispatchStatusRow(Long orderId, String dispatchStatus) { }
record OrderWeightRow(Long orderId, BigDecimal grossWeightKg, BigDecimal netWeightKg) { }
@Select("<script>SELECT o.id AS orderId," +
"COALESCE(SUM(d.gross_weight_kg),MAX(i.gross_weight_kg),0) AS grossWeightKg," +
"COALESCE(SUM(d.net_weight_kg),MAX(i.net_weight_kg),0) AS netWeightKg " +
"FROM ll_order o LEFT JOIN ll_order_detail d ON d.order_id=o.id AND d.customer_id=o.customer_id " +
"LEFT JOIN ll_inbound_order i ON i.id=o.id AND i.customer_id=o.customer_id WHERE o.id IN " +
"<foreach collection='orderIds' item='id' open='(' separator=',' close=')'>#{id}</foreach> " +
"GROUP BY o.id</script>")
List<OrderWeightRow> findOrderWeights(@Param("orderIds") List<Long> orderIds);
String CONTAINER_PROGRESS_FILTER = " FROM ll_order o LEFT JOIN ll_inbound_plan p " +
"ON p.customer_id=o.customer_id AND p.source_order_id=o.id " +
"WHERE o.source_container_booking_id IS NOT NULL AND o.source_container_booking_id&lt;&gt;'' " +
@@ -48,6 +48,7 @@ import java.nio.charset.StandardCharsets;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.security.MessageDigest;
import java.util.ArrayList;
@@ -94,9 +95,11 @@ public class LastlegOrderService {
Map<Long, List<LastlegOrderMapper.PalletMergeRelationRow>> mergeRelations = palletMergeRelations(page.getRecords());
Map<String, String> containerNodes = containerNodes(page.getRecords());
Map<Long, String> dispatchStatuses = dispatchStatuses(page.getRecords());
Map<Long, LastlegOrderMapper.OrderWeightRow> weights = orderWeights(page.getRecords());
return new PageResult<>(page.getRecords().stream().map(order -> summary(order, mergeRelations.get(order.getId()),
StringUtils.hasText(order.getSourceContainerBookingId())
? containerNodes.get(order.getSourceContainerBookingId()) : null, dispatchStatuses.getOrDefault(order.getId(), "UNSCHEDULED"))).toList(),
? containerNodes.get(order.getSourceContainerBookingId()) : null,
dispatchStatuses.getOrDefault(order.getId(), "UNSCHEDULED"), weights.get(order.getId()))).toList(),
page.getCurrent(), page.getSize(), page.getTotal(), page.getPages());
}
@@ -349,7 +352,8 @@ public class LastlegOrderService {
value.getNodeCode(), value.getNodeAt(), value.getSource()))
.sorted(java.util.Comparator.comparingInt(value -> MANUAL_NODE_CODES.indexOf(value.nodeCode()))).toList();
return new LastlegOrderDetailResponse(summary(order, palletMergeRelations(List.of(order)).get(order.getId()),
containerNode(order), dispatchStatuses(List.of(order)).getOrDefault(order.getId(), "UNSCHEDULED")), manualNodes, cargo, history.stream()
containerNode(order), dispatchStatuses(List.of(order)).getOrDefault(order.getId(), "UNSCHEDULED"),
orderWeights(List.of(order)).get(order.getId())), manualNodes, cargo, history.stream()
.map(value -> new LastlegOrderDetailResponse.History(value.getId(), value.getFromStatus(),
value.getToStatus(), value.getRemark(), value.getCreatedAt())).toList(), fees, operations.stream()
.map(value -> new LastlegOrderDetailResponse.Operation(value.getId(), value.getOperationNode(),
@@ -625,8 +629,17 @@ public class LastlegOrderService {
LastlegOrderMapper.DispatchStatusRow::dispatchStatus));
}
private Map<Long, LastlegOrderMapper.OrderWeightRow> orderWeights(List<LastlegOrder> orders) {
if (orders.isEmpty()) return Map.of();
List<LastlegOrderMapper.OrderWeightRow> rows = orderMapper.findOrderWeights(
orders.stream().map(LastlegOrder::getId).toList());
if (rows == null) return Map.of();
return rows.stream().collect(Collectors.toMap(LastlegOrderMapper.OrderWeightRow::orderId, row -> row));
}
private LastlegOrderSummary summary(LastlegOrder o, List<LastlegOrderMapper.PalletMergeRelationRow> relations,
String containerNode, String dispatchStatus) {
String containerNode, String dispatchStatus,
LastlegOrderMapper.OrderWeightRow weight) {
List<LastlegOrderMapper.PalletMergeRelationRow> related = relations == null ? List.of() : relations;
return new LastlegOrderSummary(o.getId(), displayOrderNo(o), o.getOrderType(),
LastlegOrderType.labelOf(o.getOrderType()), o.getDestinationType(), o.getSourceInboundId(),
@@ -637,7 +650,8 @@ public class LastlegOrderService {
o.getAbnormal(), o.getDetained(), o.getHoldChargeable(), o.getHoldReason(),
Boolean.TRUE.equals(o.getManualNodeOverride()), Boolean.TRUE.equals(o.getManualNodeOverride()) ? "MANUAL" : "CONTAINER",
o.getVersion() == null ? 0 : o.getVersion(), o.getPalletCount(), o.getPackageCount(),
o.getReceivedPackageCount(), packageDifference(o), o.getVolumeCbm(),
o.getReceivedPackageCount(), packageDifference(o), weight == null ? BigDecimal.ZERO : weight.grossWeightKg(),
weight == null ? BigDecimal.ZERO : weight.netWeightKg(), o.getVolumeCbm(),
o.getProductQuantity(), o.getVolumeWeightKg(), o.getEstimatedArrivalAt(), o.getActualArrivalAt(),
o.getEstimatedWarehouseAt(), o.getInboundOrderNo(), dispatchStatus, o.getRelabelOrderNo(), relabelBusinessStatus(o.getRelabelStatus()),
o.getPalletMergeFlag(), related.stream().map(LastlegOrderMapper.PalletMergeRelationRow::mergeGroupNo).distinct().findFirst().orElse(null),