feat(phase4): automate overseas PDA inbound lifecycle

This commit is contained in:
2026-08-24 15:38:28 +08:00
parent ef9f253f47
commit 6aca41427c
19 changed files with 377 additions and 9 deletions
@@ -6,6 +6,8 @@ import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param;
import org.apache.ibatis.annotations.Select;
import java.util.List;
@Mapper
public interface InboundPlanCartonMapper extends BaseMapper<InboundPlanCarton> {
@Select("""
@@ -31,4 +33,13 @@ public interface InboundPlanCartonMapper extends BaseMapper<InboundPlanCarton> {
WHERE l.plan_id=#{planId})
""")
boolean hasLabelPool(@Param("planId") Long planId);
@Select("""
SELECT DISTINCT c.* FROM ll_inbound_plan_carton c
JOIN ll_order_detail d ON d.source_inbound_detail_id=c.source_inbound_detail_id
JOIN ll_inbound_plan_line l ON l.order_id=d.order_id
WHERE l.plan_id=#{planId} AND c.customer_id=l.customer_id
ORDER BY c.id
""")
List<InboundPlanCarton> listExpected(@Param("planId") Long planId);
}
@@ -11,7 +11,8 @@ public final class PdaResponses {
LocalDateTime pushedAt, LocalDateTime startedAt, LocalDateTime completedAt,
List<Long> unloadPhotoFileIds, LocalDateTime unloadPhotoUploadedAt,
LocalDateTime estimatedEmptyReturnAt,
List<Pallet> pallets, List<Allocation> allocations) {}
List<Pallet> pallets, List<Allocation> allocations,
List<ExpectedCarton> expectedCartons) {}
public record Pallet(long planPalletId, String palletNo, String destinationWarehouseId,
String destinationWarehouseCode, String destinationWarehouseName,
@@ -24,6 +25,10 @@ public final class PdaResponses {
int countedPackageCount, int pickedPackageCount,
String status, int version) {}
public record ExpectedCarton(String cartonMark, String skuCode,
String destinationWarehouseId, String destinationWarehouseCode,
long planPalletId, String status) {}
public record UnloadPhotoFile(long fileId, String fileName, String contentType, long sizeBytes) {}
public record Operation(String result, long allocationId, int requiredPackageCount,
@@ -63,6 +63,7 @@ public class PdaWorkflowRepository {
public List<InboundPlanCarton> cartons(Long planId) {
return cartons.selectList(new LambdaQueryWrapper<InboundPlanCarton>().eq(InboundPlanCarton::getPlanId, planId));
}
public List<InboundPlanCarton> expectedCartons(Long planId) { return cartons.listExpected(planId); }
public InboundPlanLine lineForCarton(Long planId, InboundPlanCarton carton) {
return cartons.findPlanLine(planId, carton.getSourceInboundDetailId());
}
@@ -650,9 +650,23 @@ public class InboundPdaWorkflowService {
InboundPdaWorkflowService.value(value.getPickedPackageCount()), value.getStatus(),
InboundPdaWorkflowService.value(value.getVersion()));
}).toList();
List<PdaResponses.ExpectedCarton> expectedCartons = repository.expectedCartons(task.getPlanId()).stream()
.map(value -> new PdaResponses.ExpectedCarton(value.getCartonMark(), value.getSkuCode(),
value.getDestinationWarehouseId(), value.getDestinationWarehouseCode(),
recommendedPallet(value, planPallets), value.getStatus()))
.toList();
return new PdaResponses.Task(task.getId(), task.getTaskNo(), planNo, task.getStatus(),
task.getPushedAt(), task.getStartedAt(), task.getCompletedAt(), unloadPhotoFileIds(task),
task.getUnloadPhotoUploadedAt(), task.getEstimatedEmptyReturnAt(), pallets, allocations);
task.getUnloadPhotoUploadedAt(), task.getEstimatedEmptyReturnAt(), pallets, allocations,
expectedCartons);
}
private long recommendedPallet(InboundPlanCarton carton, List<InboundPlanPallet> pallets) {
if (carton.getPlanPalletId() != null) return carton.getPlanPalletId();
return pallets.stream().filter(value -> Objects.equals(value.getDestinationWarehouseId(), carton.getDestinationWarehouseId())
|| (carton.getDestinationWarehouseId() == null
&& Objects.equals(value.getDestinationWarehouseCode(), carton.getDestinationWarehouseCode())))
.map(InboundPlanPallet::getId).findFirst().orElse(0L);
}
private List<Long> unloadPhotoFileIds(InboundPdaTask task) {
@@ -224,7 +224,8 @@ public class InboundPlanService {
private void validateOrders(List<SourceOrderSnapshot> orders) {
for (SourceOrderSnapshot order : orders) {
if (!"PENDING_ASSIGNMENT".equals(order.currentStatus())) {
if (!("PENDING_ASSIGNMENT".equals(order.currentStatus())
|| "DESTINATION_ASSIGNED".equals(order.currentStatus()))) {
throw new ResponseStatusException(HttpStatus.CONFLICT,
"Inbound code " + order.inboundCode() + " is not ready for an inbound plan");
}
@@ -9,6 +9,8 @@ import com.baiyue.lastleg.dto.LastlegOrderSummary;
import com.baiyue.lastleg.entity.LastlegOrder;
import com.baiyue.lastleg.entity.LastlegOrderDetail;
import com.baiyue.lastleg.entity.LastlegOrderStatusHistory;
import com.baiyue.lastleg.inboundplan.entity.InboundPlanCarton;
import com.baiyue.lastleg.inboundplan.mapper.InboundPlanCartonMapper;
import com.baiyue.lastleg.mapper.LastlegOrderDetailMapper;
import com.baiyue.lastleg.mapper.LastlegOrderMapper;
import com.baiyue.lastleg.mapper.LastlegOrderStatusHistoryMapper;
@@ -35,6 +37,7 @@ public class LastlegOrderService {
@Resource private LastlegOrderMapper orderMapper;
@Resource private LastlegOrderDetailMapper detailMapper;
@Resource private LastlegOrderStatusHistoryMapper historyMapper;
@Resource private InboundPlanCartonMapper cartonMapper;
public PageResult<LastlegOrderSummary> page(String customerId, LastlegOrderRequests.Query query) {
Page<LastlegOrder> page = orderMapper.selectPage(
@@ -88,8 +91,17 @@ public class LastlegOrderService {
detailUpdate.setDestinationWarehouseCode(request.warehouseCode());
detailUpdate.setDestinationWarehouseName(request.warehouseName());
detailMapper.update(detailUpdate, new LambdaQueryWrapper<LastlegOrderDetail>()
.eq(LastlegOrderDetail::getCustomerId, order.getCustomerId())
.eq(LastlegOrderDetail::getOrderId, order.getId()));
InboundPlanCarton cartonUpdate = new InboundPlanCarton();
cartonUpdate.setDestinationWarehouseId(request.warehouseId());
cartonUpdate.setDestinationWarehouseCode(request.warehouseCode());
cartonUpdate.setDestinationWarehouseName(request.warehouseName());
cartonMapper.update(cartonUpdate, new LambdaQueryWrapper<InboundPlanCarton>()
.eq(InboundPlanCarton::getCustomerId, order.getCustomerId())
.eq(InboundPlanCarton::getOrderId, order.getId()));
LastlegOrderStatusHistory history = new LastlegOrderStatusHistory();
history.setCustomerId(order.getCustomerId());
history.setOrderId(order.getId());