优化
This commit is contained in:
+2
-2
@@ -12,7 +12,7 @@ import java.util.List;
|
||||
@Mapper
|
||||
public interface DeliveryOperationMapper extends BaseMapper<DeliveryOperation> {
|
||||
|
||||
/** 普通库存流水与原箱回仓凭据共同证明实际退回,每个原箱只计一次箱数。 */
|
||||
/** 普通流水与原箱凭据证明退回,共享任务按真实扫码及逐票客户归属核验。 */
|
||||
@Select("SELECT l.id AS ledger_id, di.id AS dispatch_item_id, oi.warehouse_pallet_id AS pallet_id, " +
|
||||
"l.delta_packages AS packages, l.occurred_at AS received_at FROM ll_delivery_order d " +
|
||||
"JOIN ll_exception_order e ON e.customer_id=d.customer_id AND e.delivery_order_id=d.id " +
|
||||
@@ -25,7 +25,7 @@ public interface DeliveryOperationMapper extends BaseMapper<DeliveryOperation> {
|
||||
"AND di.warehouse_pallet_id=oi.warehouse_pallet_id " +
|
||||
"AND EXISTS (SELECT 1 FROM ll_dispatch_pda_pick p JOIN ll_dispatch_pda_pick_order a " +
|
||||
"ON a.customer_id=p.customer_id AND a.pick_id=p.id " +
|
||||
"JOIN ll_dispatch_pda_task t ON t.customer_id=p.customer_id AND t.id=p.task_id " +
|
||||
"JOIN ll_dispatch_pda_task t ON t.id=p.task_id " +
|
||||
"WHERE p.customer_id=d.customer_id AND t.dispatch_order_id=d.dispatch_order_id " +
|
||||
"AND p.dispatch_item_id=di.id AND p.inventory_position_id=i.inventory_position_id AND a.order_id=e.last_mile_order_id) " +
|
||||
"WHERE d.customer_id=#{customerId} AND d.id=#{deliveryOrderId} UNION ALL SELECT MIN(r.id),r.source_dispatch_item_id,oi.warehouse_pallet_id,SUM(r.packages),r.received_at " +
|
||||
|
||||
+1
-1
@@ -17,7 +17,7 @@ public interface DispatchFeeCargoMapper {
|
||||
JOIN ll_inventory_balance b ON b.id=p.balance_id AND b.customer_id=di.customer_id
|
||||
LEFT JOIN ll_order o ON o.id=b.inbound_order_id AND o.customer_id=di.customer_id
|
||||
LEFT JOIN (SELECT pk.dispatch_item_id,pk.inventory_position_id,SUM(pk.packages) AS packages
|
||||
FROM ll_dispatch_pda_pick pk JOIN ll_dispatch_pda_task task ON task.id=pk.task_id AND task.customer_id=pk.customer_id
|
||||
FROM ll_dispatch_pda_pick pk JOIN ll_dispatch_pda_task task ON task.id=pk.task_id
|
||||
WHERE task.dispatch_order_id=#{dispatchId} AND pk.customer_id=#{customerId}
|
||||
GROUP BY pk.dispatch_item_id,pk.inventory_position_id) picked
|
||||
ON picked.dispatch_item_id=di.id AND picked.inventory_position_id=p.id
|
||||
|
||||
+8
@@ -45,6 +45,14 @@ public class DeliveryCancellationRepository {
|
||||
public OutboundOrder lock(String no) { return outbounds.lockGlobalByNo(no); }
|
||||
/** 独立换标出库保留其原域确认锁。 */
|
||||
public RelabelApplication lockRelabel(OutboundOrder order) { return relabels.lockByOutbound(order.getCustomerId(),order.getOutboundNo()); }
|
||||
/** 仅撤销本次出库关联,原生箱和普通仓托均保留客户已确认成果;旧号必须显式清空。 */
|
||||
public boolean restoreRelabelArrangement(RelabelApplication application,String outboundNo,String fulfillment,LocalDateTime now) {
|
||||
return relabels.update(null,new LambdaUpdateWrapper<RelabelApplication>()
|
||||
.eq(RelabelApplication::getId,application.getId()).eq(RelabelApplication::getCustomerId,application.getCustomerId())
|
||||
.eq(RelabelApplication::getOutboundOrderNo,outboundNo).eq(RelabelApplication::getStatus,"READY_FOR_OUTBOUND")
|
||||
.set(RelabelApplication::getOutboundOrderNo,null).set(RelabelApplication::getFulfillmentStatus,fulfillment)
|
||||
.set(RelabelApplication::getUpdatedAt,now))==1;
|
||||
}
|
||||
/** 子明细始终按出库客户读取。 */
|
||||
public List<OutboundPalletItem> items(OutboundOrder order) { return items.findByOutbound(order.getCustomerId(),order.getId()); }
|
||||
/** 一次取得本出库全部派送锁,不边持来源锁边锁下一张派送。 */
|
||||
|
||||
+21
-10
@@ -1,6 +1,5 @@
|
||||
package com.baiyue.lastleg.delivery.service;
|
||||
|
||||
import com.baiyue.lastleg.fleet.trip.FleetDispatchBindingGuard;
|
||||
import com.baiyue.lastleg.fleet.trip.FleetDispatchGateway;
|
||||
|
||||
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||
@@ -22,9 +21,9 @@ import com.baiyue.lastleg.delivery.mapper.DeliveryOperationMapper;
|
||||
import com.baiyue.lastleg.delivery.mapper.OutboundOrderMapper;
|
||||
import com.baiyue.lastleg.delivery.mapper.OutboundPalletItemMapper;
|
||||
import com.baiyue.lastleg.dispatch.entity.DispatchItem;
|
||||
import com.baiyue.lastleg.dispatch.entity.DispatchOrder;
|
||||
import com.baiyue.lastleg.dispatch.mapper.DispatchItemMapper;
|
||||
import com.baiyue.lastleg.dispatch.mapper.DispatchOrderMapper;
|
||||
import com.baiyue.lastleg.dispatch.entity.DispatchAggregate;
|
||||
import com.baiyue.lastleg.dispatch.repository.DispatchAggregateRepository;
|
||||
import com.baiyue.lastleg.entity.LastlegOrder;
|
||||
import com.baiyue.lastleg.entity.LastlegOrderStatusHistory;
|
||||
import com.baiyue.lastleg.entity.LastlegOrderDetail;
|
||||
@@ -93,7 +92,7 @@ import java.util.stream.Collectors;
|
||||
|
||||
@Service
|
||||
public class DeliveryTransferService {
|
||||
@Resource private DispatchOrderMapper dispatchOrders;
|
||||
@Resource private DispatchAggregateRepository dispatches;
|
||||
@Resource private DispatchItemMapper dispatchItems;
|
||||
@Resource private OutboundOrderMapper outboundOrders;
|
||||
@Resource private OutboundPalletItemMapper outboundPallets;
|
||||
@@ -128,7 +127,6 @@ public class DeliveryTransferService {
|
||||
@Resource private RelabelApplicationService relabelService;
|
||||
@Resource private LastlegOrderNoGenerator orderNoGenerator;
|
||||
@Resource private ObjectMapper objectMapper;
|
||||
@Resource private FleetDispatchBindingGuard fleetBindings;
|
||||
@Resource private DeliveryExecutionGuard deliveryExecution;
|
||||
@Resource private com.baiyue.lastleg.dispatch.port.DispatchExecutionPort execution;
|
||||
@Resource private com.baiyue.lastleg.delivery.repository.DeliveryCancellationRepository cancellations;
|
||||
@@ -912,7 +910,7 @@ public class DeliveryTransferService {
|
||||
|| dispatch.stage()!=com.baiyue.lastleg.dispatch.port.DispatchTypes.Stage.BEFORE_LOADING
|
||||
|| dispatch.counts()==null || dispatch.counts().pickedPackageCount()>0 || dispatch.counts().shippedPackageCount()>0)
|
||||
throw conflict("排车已开始执行,不能直接取消出库");
|
||||
fleetBindings.requireUnbound(dispatch.dispatchId());
|
||||
// 唯一Fleet资源记录随整车自动创建,不能把本车正常关系当作额外取消阻断。
|
||||
}
|
||||
if (!Set.of("WAIT_OUTBOUND", "WAIT_PICK").contains(outbound.getStatus())) {
|
||||
throw conflict("Only an unexecuted outbound order can be cancelled");
|
||||
@@ -923,6 +921,8 @@ public class DeliveryTransferService {
|
||||
|| !Set.of("WAIT_PICK", "WAIT_OUTBOUND").contains(i.getStatus()))) {
|
||||
throw conflict("Outbound order cannot be cancelled after execution has started");
|
||||
}
|
||||
boolean relabelArrangement = "RELABEL_OUTBOUND".equals(outbound.getOutboundType());
|
||||
String pendingRelabelFulfillment = null;
|
||||
List<DeliveryOrder> existingDeliveries = cancellations.deliveries(outbound);
|
||||
if (existingDeliveries.stream().anyMatch(delivery -> !"WAIT_DELIVERY".equals(delivery.getStatus())))
|
||||
throw conflict("Outbound order cannot be cancelled while delivery is in progress");
|
||||
@@ -932,6 +932,7 @@ public class DeliveryTransferService {
|
||||
if ("RELABEL_OUTBOUND".equals(outbound.getOutboundType())) {
|
||||
if (application == null || !customerId.equals(application.getCustomerId())
|
||||
|| !outbound.getOutboundNo().equals(application.getOutboundOrderNo())
|
||||
|| !Objects.equals(outbound.getOverseasWarehouseId(),application.getOverseasWarehouseId())
|
||||
|| !RelabelApplicationService.READY_FOR_OUTBOUND.equals(application.getStatus()))
|
||||
throw conflict("换标出库关联状态已变化,不能取消");
|
||||
for (OutboundPalletItem item : outboundItems) {
|
||||
@@ -939,6 +940,7 @@ public class DeliveryTransferService {
|
||||
for (String mark : Objects.toString(item.getCartonMarks(), "").split(",")) {
|
||||
ReturnInventoryCarton carton = cancellations.lockCarton(mark);
|
||||
if (carton == null || !customerId.equals(carton.getCustomerId())
|
||||
|| !Objects.equals(outbound.getOverseasWarehouseId(),carton.getOverseasWarehouseId())
|
||||
|| !Objects.equals(application.getId(), carton.getRelabelApplicationId())
|
||||
|| !"OUTBOUND_PENDING".equals(carton.getStatus()))
|
||||
throw conflict("退货换标箱预留状态异常,不能取消出库");
|
||||
@@ -946,8 +948,10 @@ public class DeliveryTransferService {
|
||||
cancellations.save(carton);
|
||||
}
|
||||
}
|
||||
relabelService.changeStatus(customerId, application.getRelabelNo(), operatorId,
|
||||
new RelabelRequests.ChangeStatus("CANCELLED", request.reason().trim()));
|
||||
// 原生箱和普通仓托均只撤销本次安排;整车分支仍须先通过父锁、阶段和零扫码门禁。
|
||||
pendingRelabelFulfillment = "TRUCK".equals(application.getDeliveryMethod()) ? "WAIT_PRE_DISPATCH" : "WAIT_OUTBOUND_CREATION";
|
||||
if (!cancellations.restoreRelabelArrangement(application,outbound.getOutboundNo(),pendingRelabelFulfillment,now))
|
||||
throw conflict("原换标出库关联已变化,未取消本次安排");
|
||||
}
|
||||
if ("RETURN_OUTBOUND".equals(outbound.getOutboundType())) {
|
||||
for (String mark : outboundItems.stream().map(OutboundPalletItem::getCartonMarks).sorted().toList()) {
|
||||
@@ -968,6 +972,13 @@ public class DeliveryTransferService {
|
||||
var current=cancellations.lockSource(customerId,selected.getId());
|
||||
if(current!=null && outboundNo.equals(current.getOutboundOrderNo()))cancelSources.put(current.getId(),current);
|
||||
}
|
||||
if (relabelArrangement) {
|
||||
// 仅清本次出库/派送关联,来源主状态和换标完成事实保持原值,不能退回未换标库存。
|
||||
for (var order : cancelSources.values()) {
|
||||
if (!cancellations.restore(order,outboundNo,order.getCurrentStatus(),"RELABEL:"+pendingRelabelFulfillment,now))
|
||||
throw conflict("原换标来源出库关联已变化,请刷新核对");
|
||||
}
|
||||
}
|
||||
for (DeliveryOrder delivery : existingDeliveries) {
|
||||
int voidRequests = 0;
|
||||
for (var fee : feeSources.listForBusiness(customerId, "DELIVERY_ORDER", delivery.getId())) {
|
||||
@@ -1066,7 +1077,7 @@ public class DeliveryTransferService {
|
||||
OutboundOrder outbound = outboundOrders.findGlobalByNo(code);
|
||||
if (outbound != null && boundWarehouseId.equals(outbound.getOverseasWarehouseId())) {
|
||||
if ("DISPATCH_DELIVERY".equals(outbound.getOutboundType()) && StringUtils.hasText(outbound.getDispatchNo())) {
|
||||
DispatchOrder dispatch = dispatchOrders.findGlobalByDispatchNo(outbound.getDispatchNo());
|
||||
DispatchAggregate dispatch = dispatches.find(outbound.getDispatchNo());
|
||||
if (dispatch != null && boundWarehouseId.equals(dispatch.getOverseasWarehouseId())) {
|
||||
return new DeliveryResponses.PdaTaskResolution("DISPATCH", null, outbound.getOutboundNo(),
|
||||
dispatch.getDispatchNo());
|
||||
@@ -1076,7 +1087,7 @@ public class DeliveryTransferService {
|
||||
if (task != null) return outboundResolution(outbound, task);
|
||||
}
|
||||
|
||||
DispatchOrder dispatch = dispatchOrders.findGlobalByDispatchNo(code);
|
||||
DispatchAggregate dispatch = dispatches.find(code);
|
||||
if (dispatch != null && boundWarehouseId.equals(dispatch.getOverseasWarehouseId())) {
|
||||
return new DeliveryResponses.PdaTaskResolution("DISPATCH", null, null, dispatch.getDispatchNo());
|
||||
}
|
||||
|
||||
-57
@@ -1,57 +0,0 @@
|
||||
package com.baiyue.lastleg.delivery.service;
|
||||
|
||||
import com.baiyue.lastleg.dispatch.entity.DispatchItem;
|
||||
import com.baiyue.lastleg.dispatch.entity.DispatchOrder;
|
||||
import com.baiyue.lastleg.delivery.repository.DispatchCargoSourceRepository;
|
||||
import com.baiyue.lastleg.fleet.trip.FleetDispatchGateway;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.web.server.ResponseStatusException;
|
||||
import java.util.*;
|
||||
|
||||
/** 外接绑定和约定运费共同消费同一份逐来源货物。 */
|
||||
@Service
|
||||
public class DispatchCargoSourceQuery {
|
||||
private final DispatchCargoSourceRepository repository;
|
||||
/** 装配当前库存与本次拣货的真实来源入口。 */
|
||||
public DispatchCargoSourceQuery(DispatchCargoSourceRepository repository) { this.repository = repository; }
|
||||
|
||||
/** 新增普通派送应收只绑定真实未约定来源;混合多票时保留派送归属。 */
|
||||
public Set<Long> ordinaryOrderIds(DispatchOrder dispatch, Set<String> externalInboundCodes) {
|
||||
return repository.sources(dispatch.getCustomerId(), dispatch.getId()).stream()
|
||||
.filter(row -> !externalInboundCodes.contains(row.inboundCode()))
|
||||
.map(row -> row.orderId()).filter(Objects::nonNull).collect(java.util.stream.Collectors.toSet());
|
||||
}
|
||||
|
||||
/** 每条普通排车明细核平实际组成;箱级换标和退货保留其专用来源快照。 */
|
||||
public List<FleetDispatchGateway.SourceCargo> sources(DispatchOrder dispatch, List<DispatchItem> items) {
|
||||
if (items.isEmpty()) return List.of();
|
||||
var rows = repository.sources(dispatch.getCustomerId(), dispatch.getId());
|
||||
var result = new ArrayList<FleetDispatchGateway.SourceCargo>();
|
||||
for (var item : items) {
|
||||
String destination = FleetDispatchGateway.destinationKey(item.getDestinationType(),
|
||||
item.getDestinationWarehouseCode(), item.getFbaWarehouseCode(), item.getDeliveryAddress(), item.getPostalCode());
|
||||
// 实收重派按不可变实收记录选货,箱级换标按箱来源选货;都不是普通整托候选。
|
||||
if (item.getReturnReceiptId() != null || Set.of("RELABEL", "RETURN_RELABEL").contains(Objects.toString(item.getSourceStage(), ""))) {
|
||||
result.add(new FleetDispatchGateway.SourceCargo(item.getInboundCode(),
|
||||
item.getWarehousePalletId() == null ? null : item.getWarehousePalletId().toString(),
|
||||
item.getPalletNo(), Objects.requireNonNullElse(item.getPackageCount(), 0), destination));
|
||||
continue;
|
||||
}
|
||||
var selected = rows.stream().filter(row -> Objects.equals(row.dispatchItemId(), item.getId())).toList();
|
||||
if (selected.isEmpty() || item.getPackageCount() == null || selected.stream().mapToLong(row -> row.packages()).sum() != item.getPackageCount())
|
||||
throw conflict("实际货物组成与排车箱数不一致,请核对收货、托盘及本次拣货来源");
|
||||
for (var row : selected) {
|
||||
if (row.inboundCode() == null || row.inboundCode().isBlank() || row.packages() <= 0
|
||||
|| !Objects.equals(row.warehousePalletId(), item.getWarehousePalletId()))
|
||||
throw conflict("货物缺少真实入仓来源或实物托盘,不能识别为普通货跳过外接核对");
|
||||
result.add(new FleetDispatchGateway.SourceCargo(row.inboundCode(), row.warehousePalletId().toString(),
|
||||
row.palletNo(), Math.toIntExact(row.packages()), destination));
|
||||
}
|
||||
}
|
||||
return List.copyOf(result);
|
||||
}
|
||||
|
||||
/** 来源不足直接阻断,不回退展示字段。 */
|
||||
private static ResponseStatusException conflict(String reason) { return new ResponseStatusException(HttpStatus.CONFLICT, reason); }
|
||||
}
|
||||
Reference in New Issue
Block a user