This commit is contained in:
2026-10-20 14:22:31 +08:00
parent 19745e46c1
commit a870b920fe
95 changed files with 2616 additions and 275 deletions
@@ -77,6 +77,14 @@ public class MerchantWarehouseTransferController {
return ApiResponse.success(service.submit(customer(user), transferNo, operator(user)));
}
/** 客户当前筛选的全部转运数量,不受页码影响。 */
@GetMapping("/quantities")
@PreAuthorize("hasAuthority('" + OverseasPermissions.MERCHANT_TRANSFER_LIST + "')")
public ApiResponse<com.baiyue.lastleg.transfer.dto.TransferQuantityTotals> quantities(
@AuthenticationPrincipal AuthenticatedUser user,@Valid WarehouseTransferRequests.Query query) {
return ApiResponse.success(service.quantityTotals(customer(user),query));
}
@GetMapping
@PreAuthorize("hasAuthority('" + OverseasPermissions.MERCHANT_TRANSFER_LIST + "')")
public ApiResponse<PageResult<WarehouseTransferResponses.Summary>> page(@AuthenticationPrincipal AuthenticatedUser user,
@@ -0,0 +1,8 @@
package com.baiyue.lastleg.transfer.dto;
/** 全筛选结果汇总,不受分页影响;已知小计与未知票数同时返回。 */
public record TransferQuantityTotals(long orderCount, Long declaredPieceCount, long knownDeclaredPieceCount,
long unknownDeclaredOrderCount, Long receivedPieceCount, long knownReceivedPieceCount,
long unknownReceivedOrderCount, long declaredCartonCount, long receivedCartonCount,
long receivedPalletCount, long availableCartonCount, long shippedCartonCount,
long remainingPalletCount, long shippedPalletCount) { }
@@ -0,0 +1,6 @@
package com.baiyue.lastleg.transfer.dto;
/** 分离客户预报、历史实收和当前箱状态;未知件数保持空值。 */
public record TransferQuantityView(Long lastlegOrderId, Long declaredPieceCount, Long receivedPieceCount,
long declaredCartonCount, long receivedCartonCount, long receivedPalletCount,
long availableCartonCount, long shippedCartonCount, long remainingPalletCount, long shippedPalletCount) { }
@@ -212,7 +212,10 @@ public final class WarehouseTransferRequests {
public record Query(@Min(1) long page, @Min(1) @Max(200) long size,
String transferNo, String inboundCode, String operatingWarehouseId,
String fbaWarehouseCode, String status, Boolean needRelabel,
LocalDateTime createdFrom, LocalDateTime createdTo) {
LocalDateTime createdFrom, LocalDateTime createdTo,
LocalDateTime reviewedFrom, LocalDateTime reviewedTo,
LocalDateTime measuredFrom, LocalDateTime measuredTo,
LocalDateTime outboundFrom, LocalDateTime outboundTo) {
public Query { if (page == 0) page = 1; if (size == 0) size = 20; }
}
}
@@ -0,0 +1,78 @@
package com.baiyue.lastleg.transfer.mapper;
import com.baomidou.mybatisplus.core.conditions.Wrapper;
import com.baiyue.lastleg.entity.LastlegOrder;
import com.baiyue.lastleg.transfer.dto.TransferQuantityView;
import org.apache.ibatis.annotations.*;
import java.util.List;
/** 使用主订单相同筛选读取转运数量事实,不把历史实收与剩余库存相减。 */
@Mapper
public interface TransferQuantityMapper {
String SELECTED = "SELECT id,customer_id FROM ll_order ${ew.customSqlSegment}";
String RECEIVED = "c.counted_at IS NOT NULL AND c.status IN ('COUNTED','DISCARD_PENDING','DISCARDED','SHIPPED')";
String FACTS = """
SELECT t.lastleg_order_id lastlegOrderId,
(SELECT CASE WHEN COUNT(*)=0 OR COUNT(*)&lt;&gt;COUNT(i.declared_quantity) THEN NULL ELSE SUM(i.declared_quantity) END
FROM ll_warehouse_transfer_item i WHERE i.customer_id=t.customer_id AND i.transfer_order_id=t.id) declaredPieceCount,
(SELECT CASE WHEN COUNT(*)=0 OR COUNT(*)&lt;&gt;COUNT(c.counted_quantity) THEN NULL ELSE SUM(c.counted_quantity) END
FROM ll_warehouse_transfer_carton c WHERE c.customer_id=t.customer_id AND c.transfer_order_id=t.id AND
""" + RECEIVED + """
) receivedPieceCount,
t.package_count declaredCartonCount,
COALESCE(f.receivedCartonCount,0) receivedCartonCount, COALESCE(f.receivedPalletCount,0) receivedPalletCount,
COALESCE(f.availableCartonCount,0) availableCartonCount, COALESCE(f.shippedCartonCount,0) shippedCartonCount,
COALESCE(f.remainingPalletCount,0) remainingPalletCount, COALESCE(f.shippedPalletCount,0) shippedPalletCount
FROM ll_warehouse_transfer_order t JOIN (
""" + SELECTED + """
) selected ON selected.id=t.lastleg_order_id AND selected.customer_id=t.customer_id
LEFT JOIN (
SELECT c.customer_id,c.transfer_order_id,
""" + "SUM(" + RECEIVED + ") receivedCartonCount," +
"COUNT(DISTINCT CASE WHEN " + RECEIVED + " THEN p.warehouse_pallet_id END) receivedPalletCount," + """
SUM(c.status='COUNTED') availableCartonCount, SUM(c.status='SHIPPED') shippedCartonCount,
COUNT(DISTINCT CASE WHEN c.status IN ('COUNTED','DISCARD_PENDING') THEN p.warehouse_pallet_id END) remainingPalletCount,
COUNT(DISTINCT CASE WHEN c.status='SHIPPED' THEN p.warehouse_pallet_id END) shippedPalletCount
FROM ll_warehouse_transfer_carton c LEFT JOIN ll_warehouse_transfer_pallet p
ON p.id=c.transfer_pallet_id AND p.customer_id=c.customer_id
GROUP BY c.customer_id,c.transfer_order_id
) f ON f.transfer_order_id=t.id AND f.customer_id=t.customer_id
""";
/** 一次读取筛选范围或本页订单的预报及实收事实。 */
@Select("<script>" + FACTS + "</script>")
List<TransferQuantityView> rows(@Param("ew") Wrapper<LastlegOrder> filter);
/** 按真实托盘身份在完整筛选集合去重,同托部分出库可同时属于实收、剩余、出库集合。 */
@Select("<script>SELECT DISTINCT c.customer_id customerId,p.warehouse_pallet_id palletId,c.status status " +
"FROM ll_warehouse_transfer_order t JOIN (" + SELECTED + ") selected " +
"ON selected.id=t.lastleg_order_id AND selected.customer_id=t.customer_id " +
"JOIN ll_warehouse_transfer_carton c ON c.transfer_order_id=t.id AND c.customer_id=t.customer_id " +
"JOIN ll_warehouse_transfer_pallet p ON p.id=c.transfer_pallet_id AND p.customer_id=c.customer_id " +
"WHERE " + RECEIVED + " AND p.warehouse_pallet_id IS NOT NULL</script>")
List<PalletFact> pallets(@Param("ew") Wrapper<LastlegOrder> filter);
/** 物理托盘事实,保留客户隔离。 */
record PalletFact(String customerId, Long palletId, String status) { }
/** 库存转运目的仓实收依正式签收凭据;件数只取精确选箱对应原清点事实。 */
@Select("<script>SELECT t.lastleg_order_id lastlegOrderId,t.customer_id customerId,a.package_count cartonCount," +
"a.pallet_id sourcePalletId,a.status status,r.id receiptId,dp.pallet_id destinationPalletId," +
"(SELECT CASE WHEN COUNT(DISTINCT c.id)=a.package_count AND COUNT(*)=COUNT(c.counted_quantity) THEN SUM(c.counted_quantity) ELSE NULL END " +
"FROM ll_warehouse_transfer_carton chosen JOIN ll_warehouse_transfer_order origin " +
"ON origin.customer_id=t.customer_id AND origin.inbound_code=t.inbound_code AND origin.operating_warehouse_id=t.operating_warehouse_id AND origin.transfer_no=origin.inbound_code " +
"JOIN ll_warehouse_transfer_carton c ON c.customer_id=origin.customer_id AND c.transfer_order_id=origin.id " +
"AND c.carton_mark=COALESCE(NULLIF(chosen.customer_carton_mark,''),chosen.carton_mark) " +
"JOIN ll_warehouse_transfer_pallet cp ON cp.id=c.transfer_pallet_id AND cp.customer_id=c.customer_id AND cp.warehouse_pallet_id=a.pallet_id " +
"WHERE chosen.transfer_order_id=t.id AND chosen.customer_id=t.customer_id AND c.counted_at IS NOT NULL) pieceCount " +
"FROM ll_warehouse_transfer_order t JOIN (" + SELECTED + ") selected ON selected.id=t.lastleg_order_id AND selected.customer_id=t.customer_id " +
"JOIN ll_warehouse_transfer_inventory_allocation a ON a.transfer_order_id=t.id AND a.customer_id=t.customer_id " +
"LEFT JOIN ll_warehouse_transfer_receipt r ON r.allocation_id=a.id AND r.customer_id=a.customer_id " +
"LEFT JOIN ll_inventory_position dp ON dp.id=r.destination_inventory_position_id AND dp.customer_id=r.customer_id " +
"WHERE t.transfer_no&lt;&gt;t.inbound_code AND a.status IN ('RESERVED','SHIPPED','RECEIVED')</script>")
List<MovementFact> movements(@Param("ew") Wrapper<LastlegOrder> filter);
/** 每个分配来源的实际出库与目的仓签收事实。 */
record MovementFact(Long lastlegOrderId,String customerId,long cartonCount,Long sourcePalletId,String status,
Long receiptId,Long destinationPalletId,Long pieceCount) { }
}
@@ -0,0 +1,28 @@
package com.baiyue.lastleg.transfer.repository;
import com.baomidou.mybatisplus.core.conditions.Wrapper;
import com.baiyue.lastleg.entity.LastlegOrder;
import com.baiyue.lastleg.transfer.dto.TransferQuantityView;
import com.baiyue.lastleg.transfer.mapper.TransferQuantityMapper;
import jakarta.annotation.Resource;
import org.springframework.stereotype.Repository;
import java.util.List;
/** 转运数量只读持久化入口。 */
@Repository
public class TransferQuantityRepository {
@Resource private TransferQuantityMapper mapper;
@Resource private com.baiyue.lastleg.transfer.mapper.WarehouseTransferOrderMapper transfers;
/** 以客户列表相同筛选读取关联主订单,不读取分页参数。 */
public List<Long> selectedOrderIds(Wrapper<com.baiyue.lastleg.transfer.entity.WarehouseTransferOrder> filter) {
return transfers.selectList(filter).stream()
.map(com.baiyue.lastleg.transfer.entity.WarehouseTransferOrder::getLastlegOrderId)
.filter(java.util.Objects::nonNull).distinct().toList();
}
/** 读取完整筛选集合的事实,分页由主列表单独处理。 */
public List<TransferQuantityView> rows(Wrapper<LastlegOrder> filter) { return mapper.rows(filter); }
/** 读取完整筛选集合的物理托盘。 */
public List<TransferQuantityMapper.PalletFact> pallets(Wrapper<LastlegOrder> filter) { return mapper.pallets(filter); }
/** 读取库存转运实际出库及目的仓签收,按来源分配去重。 */
public List<TransferQuantityMapper.MovementFact> movements(Wrapper<LastlegOrder> filter) { return mapper.movements(filter); }
}
@@ -0,0 +1,87 @@
package com.baiyue.lastleg.transfer.service;
import com.baomidou.mybatisplus.core.conditions.Wrapper;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baiyue.lastleg.entity.LastlegOrder;
import com.baiyue.lastleg.transfer.dto.*;
import com.baiyue.lastleg.transfer.repository.TransferQuantityRepository;
import jakarta.annotation.Resource;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.util.*;
import java.util.function.ToLongFunction;
import java.util.stream.Collectors;
/** 预报、实收、当前剩余分别汇总,空件数不会被零值掩盖。 */
@Service
public class TransferQuantityService {
@Resource private TransferQuantityRepository repository;
/** 客户列表共享完整筛选,主订单查询仍显式限定客户。 */
@Transactional(readOnly=true)
public TransferQuantityTotals merchantTotals(Wrapper<com.baiyue.lastleg.transfer.entity.WarehouseTransferOrder> filter, String customerId) {
var ids = repository.selectedOrderIds(filter);
var orders = new LambdaQueryWrapper<LastlegOrder>().eq(LastlegOrder::getCustomerId, customerId);
if (ids.isEmpty()) orders.apply("1=0"); else orders.in(LastlegOrder::getId, ids);
return totals(orders);
}
/** 主列表批量加载本页转运,其他业务不改变字段语义。 */
public Map<Long,TransferQuantityView> forOrders(List<LastlegOrder> orders) {
var ids=orders.stream().filter(o -> "WAREHOUSE_TRANSFER".equals(o.getOrderType())).map(LastlegOrder::getId).toList();
if(ids.isEmpty()) return Map.of();
var filter = new LambdaQueryWrapper<LastlegOrder>().in(LastlegOrder::getId,ids);
return withMovements(repository.rows(filter),repository.movements(filter))
.stream().collect(Collectors.toMap(TransferQuantityView::lastlegOrderId, v -> v));
}
/** 同一只读事务按完整筛选汇总,page/size不参与数量计算。 */
@Transactional(readOnly=true)
public TransferQuantityTotals totals(Wrapper<LastlegOrder> filter) {
var movements=repository.movements(filter);
var rows=withMovements(repository.rows(filter),movements); var pallets=repository.pallets(filter);
long unknownDeclared=rows.stream().filter(v -> v.declaredPieceCount()==null).count();
long unknownReceived=rows.stream().filter(v -> v.receivedPieceCount()==null).count();
long declared=sum(rows,v -> v.declaredPieceCount()==null?0:v.declaredPieceCount());
long received=sum(rows,v -> v.receivedPieceCount()==null?0:v.receivedPieceCount());
var all=new HashSet<String>(); var remaining=new HashSet<String>(); var shipped=new HashSet<String>();
for(var pallet:pallets) {
String key=pallet.customerId()+":"+pallet.palletId(); all.add(key);
if(Set.of("COUNTED","DISCARD_PENDING").contains(pallet.status())) remaining.add(key);
if("SHIPPED".equals(pallet.status())) shipped.add(key);
}
for (var move:movements) {
if (move.receiptId()!=null && move.destinationPalletId()!=null) all.add(move.customerId()+":"+move.destinationPalletId());
if (Set.of("SHIPPED","RECEIVED").contains(move.status()) && move.sourcePalletId()!=null) shipped.add(move.customerId()+":"+move.sourcePalletId());
}
return new TransferQuantityTotals(rows.size(),unknownDeclared==0?declared:null,declared,unknownDeclared,
unknownReceived==0?received:null,received,unknownReceived,sum(rows,TransferQuantityView::declaredCartonCount),
sum(rows,TransferQuantityView::receivedCartonCount),all.size(),sum(rows,TransferQuantityView::availableCartonCount),
sum(rows,TransferQuantityView::shippedCartonCount),remaining.size(),shipped.size());
}
/** 库存转运的实收来自目的仓凭据,原仓出库事实保留独立维度。 */
private List<TransferQuantityView> withMovements(List<TransferQuantityView> rows,
List<com.baiyue.lastleg.transfer.mapper.TransferQuantityMapper.MovementFact> movements) {
var grouped=movements.stream().collect(Collectors.groupingBy(com.baiyue.lastleg.transfer.mapper.TransferQuantityMapper.MovementFact::lastlegOrderId));
return rows.stream().map(row -> {
var facts=grouped.get(row.lastlegOrderId()); if(facts==null) return row;
long received=0,pieces=0,shipped=0; boolean known=true; var targets=new HashSet<Long>(); var sources=new HashSet<Long>();
for(var fact:facts) {
if(fact.receiptId()!=null) {
received=Math.addExact(received,fact.cartonCount());
if(fact.pieceCount()==null) known=false; else pieces=Math.addExact(pieces,fact.pieceCount());
if(fact.destinationPalletId()!=null) targets.add(fact.destinationPalletId());
}
if(Set.of("SHIPPED","RECEIVED").contains(fact.status())) { shipped=Math.addExact(shipped,fact.cartonCount()); if(fact.sourcePalletId()!=null) sources.add(fact.sourcePalletId()); }
}
return new TransferQuantityView(row.lastlegOrderId(),row.declaredPieceCount(),received>0&&known?pieces:null,
row.declaredCartonCount(),received,targets.size(),0,shipped,0,sources.size());
}).toList();
}
/** 使用精确整数累加,溢出不能静默返回错误汇总。 */
private long sum(List<TransferQuantityView> rows,ToLongFunction<TransferQuantityView> measure) {
long value=0; for(var row:rows) value=Math.addExact(value,measure.applyAsLong(row)); return value;
}
}
@@ -92,6 +92,7 @@ import java.util.stream.Collectors;
@Service
public class WarehouseTransferService {
@Resource private TransferQuantityService transferQuantityService;
@Resource private com.baiyue.lastleg.fleet.pickup.FleetPickupService pickupService;
/** 退货单在转运来源中的展示编码,避免把退货单号误当成普通入仓码查询。 */
public static final String RETURN_ORDER_PREFIX = "RETURN_ORDER:";
@@ -551,19 +552,15 @@ public class WarehouseTransferService {
transferCartons.updateById(carton);
}
}
@Transactional(readOnly = true)
public PageResult<WarehouseTransferResponses.Summary> page(String customerId, WarehouseTransferRequests.Query query) {
return page(customerId, query, true);
}
@Transactional(readOnly = true)
public PageResult<WarehouseTransferResponses.Summary> page(String customerId, WarehouseTransferRequests.Query query,
boolean includeDrafts) {
if (query.createdFrom() != null && query.createdTo() != null && query.createdFrom().isAfter(query.createdTo())) {
throw badRequest("createdFrom must not be after createdTo");
}
/** 列表和全筛选数量共享条件,避免翻页或状态分组后口径漂移。 */
private LambdaQueryWrapper<WarehouseTransferOrder> transferPageFilter(String customerId,
WarehouseTransferRequests.Query query, boolean includeDrafts) {
validateQuantityRange(query.createdFrom(), query.createdTo(), "创建");
validateQuantityRange(query.reviewedFrom(), query.reviewedTo(), "审核");
validateQuantityRange(query.measuredFrom(), query.measuredTo(), "清点完成");
validateQuantityRange(query.outboundFrom(), query.outboundTo(), "出库");
List<String> groupedStatuses = customerMainStatuses(query.status());
LambdaQueryWrapper<WarehouseTransferOrder> wrapper = new LambdaQueryWrapper<WarehouseTransferOrder>()
return new LambdaQueryWrapper<WarehouseTransferOrder>()
.eq(StringUtils.hasText(customerId), WarehouseTransferOrder::getCustomerId, customerId)
.like(StringUtils.hasText(query.transferNo()), WarehouseTransferOrder::getTransferNo, query.transferNo())
.like(StringUtils.hasText(query.inboundCode()), WarehouseTransferOrder::getInboundCode, query.inboundCode())
@@ -577,7 +574,35 @@ public class WarehouseTransferService {
.eq(query.needRelabel() != null, WarehouseTransferOrder::getNeedRelabel, query.needRelabel())
.ge(query.createdFrom() != null, WarehouseTransferOrder::getCreatedAt, query.createdFrom())
.le(query.createdTo() != null, WarehouseTransferOrder::getCreatedAt, query.createdTo())
.ge(query.reviewedFrom() != null, WarehouseTransferOrder::getReviewedAt, query.reviewedFrom())
.le(query.reviewedTo() != null, WarehouseTransferOrder::getReviewedAt, query.reviewedTo())
.ge(query.outboundFrom() != null, WarehouseTransferOrder::getOutboundAt, query.outboundFrom())
.le(query.outboundTo() != null, WarehouseTransferOrder::getOutboundAt, query.outboundTo())
.apply(query.measuredFrom() != null, "(SELECT MAX(qp.completed_at) FROM ll_warehouse_transfer_pallet qp WHERE qp.transfer_order_id=ll_warehouse_transfer_order.id AND qp.customer_id=ll_warehouse_transfer_order.customer_id) >= {0}", query.measuredFrom())
.apply(query.measuredTo() != null, "(SELECT MAX(qp.completed_at) FROM ll_warehouse_transfer_pallet qp WHERE qp.transfer_order_id=ll_warehouse_transfer_order.id AND qp.customer_id=ll_warehouse_transfer_order.customer_id) <= {0}", query.measuredTo())
.orderByDesc(WarehouseTransferOrder::getCreatedAt).orderByDesc(WarehouseTransferOrder::getId);
}
/** 日期区间统一校验,列表与数量汇总均拒绝反向区间。 */
private void validateQuantityRange(LocalDateTime from, LocalDateTime to, String name) {
if (from != null && to != null && from.isAfter(to)) throw badRequest(name + "开始时间不能晚于结束时间");
}
/** 客户侧完整筛选数量,不读取其他客户且不使用页码。 */
@Transactional(readOnly = true)
public com.baiyue.lastleg.transfer.dto.TransferQuantityTotals quantityTotals(String customerId, WarehouseTransferRequests.Query query) {
return transferQuantityService.merchantTotals(transferPageFilter(customerId, query, true), customerId);
}
@Transactional(readOnly = true)
public PageResult<WarehouseTransferResponses.Summary> page(String customerId, WarehouseTransferRequests.Query query) {
return page(customerId, query, true);
}
@Transactional(readOnly = true)
public PageResult<WarehouseTransferResponses.Summary> page(String customerId, WarehouseTransferRequests.Query query,
boolean includeDrafts) {
var wrapper = transferPageFilter(customerId, query, includeDrafts);
Page<WarehouseTransferOrder> result = transfers.selectPage(Page.of(query.page(), query.size()), wrapper);
Map<String, RelabelApplication> relabelApplicationsByNo = relabelApplications(result.getRecords());
Map<Long, LocalDateTime> measurementTimes = measurementTimes(result.getRecords());
@@ -961,7 +986,7 @@ public class WarehouseTransferService {
WarehouseTransferRequests.CountCartons request) {
WarehouseTransferOrder transfer = transfers.lockForPda(transferNo, String.valueOf(warehouseId));
if (transfer == null) throw notFound("当前仓没有该转运单");
if ("WAREHOUSE_PICKUP".equals(transfer.getDeliveryMethod())) pickupService.requireArrived(transfer);
if ("WAREHOUSE_PICKUP".equals(transfer.getDeliveryMethod())) pickupService.requireArrived(transfer.getId(), transfer.getDeliveryMethod(), transfer.getTransferNo(), transfer.getInboundCode());
String customerId = transfer.getCustomerId();
List<WarehouseTransferCarton> cartons = transferCartons.listOrder(customerId, transfer.getId());
// 客户补箱后旧设备快照不可确认短收,必须刷新取得新增的预报箱唛。
@@ -1096,7 +1121,11 @@ public class WarehouseTransferService {
/** 上门取货必须先送仓;按 PDA 绑定仓锁定后继续使用原测量流程。 */
private WarehouseTransferOrder requirePdaMeasuringTransfer(long warehouseId, String transferNo) {
return pickupService.requireMeasuringSource(String.valueOf(warehouseId), transferNo);
WarehouseTransferOrder transfer = transfers.lockForPda(transferNo, String.valueOf(warehouseId));
if (transfer == null) throw notFound("仓储转运单不存在");
if (!WAIT_PDA_RECEIVING.equals(transfer.getStatus())) throw conflict("当前转运单不允许测量");
pickupService.requireArrived(transfer.getId(), transfer.getDeliveryMethod(), transfer.getTransferNo(), transfer.getInboundCode());
return transfer;
}
private void validatePalletMeasurement(BigDecimal length, BigDecimal width, BigDecimal height, BigDecimal volume) {
@@ -1114,7 +1143,7 @@ public class WarehouseTransferService {
WarehouseTransferRequests.Palletize request) {
WarehouseTransferOrder transfer = transfers.lockForPda(transferNo, String.valueOf(overseasWarehouseId));
if (transfer == null) throw notFound("Warehouse transfer order not found");
if ("WAREHOUSE_PICKUP".equals(transfer.getDeliveryMethod())) pickupService.requireArrived(transfer);
if ("WAREHOUSE_PICKUP".equals(transfer.getDeliveryMethod())) pickupService.requireArrived(transfer.getId(), transfer.getDeliveryMethod(), transfer.getTransferNo(), transfer.getInboundCode());
if (!String.valueOf(overseasWarehouseId).equals(transfer.getOperatingWarehouseId())) {
throw new ResponseStatusException(HttpStatus.FORBIDDEN, "Warehouse transfer belongs to another warehouse");
}
@@ -1683,7 +1712,7 @@ public class WarehouseTransferService {
String transferNo, MultipartFile file) {
WarehouseTransferOrder transfer = transfers.lockForPda(transferNo, String.valueOf(overseasWarehouseId));
if (transfer == null) throw notFound("Warehouse transfer order not found");
if ("WAREHOUSE_PICKUP".equals(transfer.getDeliveryMethod())) pickupService.requireArrived(transfer);
if ("WAREHOUSE_PICKUP".equals(transfer.getDeliveryMethod())) pickupService.requireArrived(transfer.getId(), transfer.getDeliveryMethod(), transfer.getTransferNo(), transfer.getInboundCode());
if (!WAIT_PDA_RECEIVING.equals(transfer.getStatus())) {
throw conflict("Measurement photos can only be uploaded before palletization completes");
}