Merge origin/dev and resolve backend conflicts
This commit is contained in:
+11
-2
@@ -42,6 +42,15 @@ public class DeliveryTransferController {
|
||||
return ApiResponse.success(service.createOneClick(requiredCustomer(user, customerId), operator(user), request));
|
||||
}
|
||||
|
||||
@GetMapping("/outbound-orders/one-click-dropship/candidates")
|
||||
@PreAuthorize("hasAuthority('" + OverseasPermissions.OUTBOUND_CREATE + "')")
|
||||
@Operation(summary = "List server-authoritative one-click dropship outbound candidates")
|
||||
public ApiResponse<java.util.List<DeliveryResponses.OneClickCandidate>> oneClickCandidates(
|
||||
@AuthenticationPrincipal AuthenticatedUser user, @RequestParam String customerId,
|
||||
@RequestParam(required = false) String warehouseId) {
|
||||
return ApiResponse.success(service.oneClickCandidates(requiredCustomer(user, customerId), warehouseId));
|
||||
}
|
||||
|
||||
@GetMapping("/outbound-orders")
|
||||
@PreAuthorize("hasAuthority('" + OverseasPermissions.OUTBOUND_LIST + "')")
|
||||
public ApiResponse<PageResult<DeliveryResponses.OutboundRow>> outboundPage(
|
||||
@@ -55,9 +64,9 @@ public class DeliveryTransferController {
|
||||
@PreAuthorize("hasAuthority('" + OverseasPermissions.OUTBOUND_LIST + "')")
|
||||
public ApiResponse<DeliveryResponses.OutboundDetail> outboundDetail(
|
||||
@AuthenticationPrincipal AuthenticatedUser user,
|
||||
@PathVariable String outboundNo, @Valid DeliveryRequests.PalletQuery query) {
|
||||
@PathVariable String outboundNo) {
|
||||
requirePlatform(user);
|
||||
return ApiResponse.success(service.outboundDetail(outboundNo, query));
|
||||
return ApiResponse.success(service.outboundDetail(outboundNo));
|
||||
}
|
||||
|
||||
@PostMapping("/outbound-orders/{outboundNo}/cancel")
|
||||
|
||||
+7
@@ -34,6 +34,13 @@ public class OutboundPdaController {
|
||||
return ApiResponse.success(service.pdaTasks(String.valueOf(identity.overseasWarehouseId()), status));
|
||||
}
|
||||
|
||||
@GetMapping("/resolve/{businessNo}")
|
||||
public ApiResponse<DeliveryResponses.PdaTaskResolution> resolve(
|
||||
@AuthenticationPrincipal AuthenticatedUser user, @PathVariable String businessNo) {
|
||||
PdaWarehouseIdentity identity = PdaWarehouseIdentity.require(user);
|
||||
return ApiResponse.success(service.resolvePdaTask(String.valueOf(identity.overseasWarehouseId()), businessNo));
|
||||
}
|
||||
|
||||
@GetMapping("/{taskNo}")
|
||||
public ApiResponse<DeliveryResponses.PdaTaskDetail> detail(@AuthenticationPrincipal AuthenticatedUser user,
|
||||
@PathVariable String taskNo) {
|
||||
|
||||
+9
-3
@@ -24,7 +24,7 @@ public final class DeliveryResponses {
|
||||
int packageCount, BigDecimal totalWeightKg, BigDecimal totalVolumeCbm,
|
||||
LocalDateTime plannedDeliveryAt, LocalDateTime dispatchedAt,
|
||||
LocalDateTime expectedArrivalAt, LocalDateTime signedAt,
|
||||
String remark, LocalDateTime createdAt) {}
|
||||
String remark, LocalDateTime createdAt, long version, List<String> allowedActions) {}
|
||||
|
||||
public record DeliverySku(String inboundCode, String customerName, String destinationWarehouseCode,
|
||||
String receivingAddress, String shipmentNo, String fbaTrackingNo,
|
||||
@@ -40,10 +40,16 @@ public final class DeliveryResponses {
|
||||
public record DeliveryDetail(DeliveryRow order, List<DeliverySku> skus,
|
||||
List<DeliveryFeeRow> fees, List<DeliveryOperationRow> operations) {}
|
||||
|
||||
public record OutboundPalletRow(Long id, String palletNo, String cartonMarks, String skuCode, String inboundCode,
|
||||
Integer packageCount, Integer pickedPackageCount, String status) {}
|
||||
/** 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) {}
|
||||
public record OutboundDetail(OutboundRow outbound, DeliveryRow delivery, List<OutboundPalletRow> pallets) {}
|
||||
public record OneClickCandidate(Long inventoryPositionId, String overseasWarehouseId,
|
||||
String overseasWarehouseName, String palletNo, String inboundCode,
|
||||
String skuCode, String productName, long availablePackages) {}
|
||||
public record PdaTask(Long id, String taskNo, String status, String outboundNo, LocalDateTime pushedAt, LocalDateTime completedAt) {}
|
||||
public record PdaTaskResolution(String workflow, String taskNo, String outboundNo, String dispatchNo) {}
|
||||
public record PdaPickPosition(Long inventoryPositionId, String palletNo, String cartonMark,
|
||||
String skuCode, String inboundCode, long availablePackages,
|
||||
long pickedPackages) {}
|
||||
|
||||
@@ -47,6 +47,7 @@ public class DeliveryOrder {
|
||||
private String remark;
|
||||
private String idempotencyKey;
|
||||
private String createdBy;
|
||||
private Long version;
|
||||
private LocalDateTime createdAt;
|
||||
private LocalDateTime updatedAt;
|
||||
}
|
||||
|
||||
+2
@@ -10,6 +10,8 @@ import org.apache.ibatis.annotations.Select;
|
||||
public interface DeliveryOrderMapper extends BaseMapper<DeliveryOrder> {
|
||||
@Select("SELECT * FROM ll_delivery_order WHERE customer_id=#{customerId} AND delivery_no=#{deliveryNo} LIMIT 1")
|
||||
DeliveryOrder findByNo(@Param("customerId") String customerId, @Param("deliveryNo") String deliveryNo);
|
||||
@Select("SELECT * FROM ll_delivery_order WHERE customer_id=#{customerId} AND delivery_no=#{deliveryNo} LIMIT 1 FOR UPDATE")
|
||||
DeliveryOrder lockByNo(@Param("customerId") String customerId, @Param("deliveryNo") String deliveryNo);
|
||||
@Select("SELECT * FROM ll_delivery_order WHERE customer_id=#{customerId} AND idempotency_key=#{key} LIMIT 1")
|
||||
DeliveryOrder findByIdempotency(@Param("customerId") String customerId, @Param("key") String key);
|
||||
@Select("SELECT * FROM ll_delivery_order WHERE customer_id=#{customerId} AND outbound_order_id=#{outboundOrderId} LIMIT 1 FOR UPDATE")
|
||||
|
||||
+6
@@ -23,6 +23,12 @@ public interface OutboundPdaTaskMapper extends BaseMapper<OutboundPdaTask> {
|
||||
"AND o.customer_id=t.customer_id WHERE t.task_no=#{taskNo} AND o.overseas_warehouse_id=#{warehouseId} LIMIT 1")
|
||||
OutboundPdaTask findByNoAndWarehouse(@Param("taskNo") String taskNo, @Param("warehouseId") String warehouseId);
|
||||
|
||||
@Select("SELECT t.* FROM ll_outbound_pda_task t JOIN ll_outbound_order o ON o.id=t.outbound_order_id " +
|
||||
"AND o.customer_id=t.customer_id WHERE t.customer_id=#{customerId} AND t.outbound_order_id=#{outboundOrderId} " +
|
||||
"AND o.overseas_warehouse_id=#{warehouseId} LIMIT 1")
|
||||
OutboundPdaTask findByOutboundAndWarehouse(@Param("customerId") String customerId,
|
||||
@Param("outboundOrderId") Long outboundOrderId, @Param("warehouseId") String warehouseId);
|
||||
|
||||
@Select("SELECT t.* FROM ll_outbound_pda_task t JOIN ll_outbound_order o ON o.id=t.outbound_order_id " +
|
||||
"AND o.customer_id=t.customer_id WHERE o.overseas_warehouse_id=#{warehouseId} " +
|
||||
"AND (#{status} IS NULL OR t.status=#{status}) ORDER BY t.pushed_at DESC LIMIT 200")
|
||||
|
||||
+38
@@ -0,0 +1,38 @@
|
||||
package com.baiyue.lastleg.delivery.model;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
public final class DeliveryStatusPolicy {
|
||||
private static final Set<String> EDITABLE_TARGETS = Set.of(
|
||||
"WAIT_DELIVERY", "DELIVERING", "DELIVERED", "REJECTED", "CANCELLED");
|
||||
private static final Map<String, Set<String>> TRANSITIONS = Map.of(
|
||||
"WAIT_DELIVERY", Set.of("DELIVERING", "DELIVERED", "REJECTED", "CANCELLED"),
|
||||
"DELIVERING", Set.of("DELIVERED", "REJECTED"),
|
||||
"DELIVERED", Set.of(),
|
||||
"REJECTED", Set.of(),
|
||||
"RETURN_PENDING", Set.of(),
|
||||
"RETURNED", Set.of(),
|
||||
"CANCELLED", Set.of());
|
||||
|
||||
private DeliveryStatusPolicy() { }
|
||||
|
||||
public static boolean isEditableTarget(String status) {
|
||||
return EDITABLE_TARGETS.contains(status);
|
||||
}
|
||||
|
||||
public static boolean canTransition(String from, String target) {
|
||||
return TRANSITIONS.getOrDefault(from, Set.of()).contains(target);
|
||||
}
|
||||
|
||||
public static List<String> allowedActions(String status) {
|
||||
return switch (status == null ? "" : status) {
|
||||
case "WAIT_DELIVERY" -> List.of(
|
||||
"START_DELIVERY", "COMPLETE_DELIVERY", "REJECT_DELIVERY", "CANCEL_DELIVERY");
|
||||
case "DELIVERING" -> List.of("COMPLETE_DELIVERY", "REJECT_DELIVERY", "MARK_RETURN");
|
||||
case "DELIVERED", "REJECTED" -> List.of("MARK_RETURN");
|
||||
default -> List.of();
|
||||
};
|
||||
}
|
||||
}
|
||||
+88
-22
@@ -12,6 +12,7 @@ import com.baiyue.lastleg.delivery.entity.DeliveryOperation;
|
||||
import com.baiyue.lastleg.delivery.entity.OutboundOrder;
|
||||
import com.baiyue.lastleg.delivery.entity.OutboundPalletItem;
|
||||
import com.baiyue.lastleg.delivery.mapper.DeliveryOrderMapper;
|
||||
import com.baiyue.lastleg.delivery.model.DeliveryStatusPolicy;
|
||||
import com.baiyue.lastleg.delivery.mapper.DeliveryFeeMapper;
|
||||
import com.baiyue.lastleg.delivery.mapper.DeliveryOperationMapper;
|
||||
import com.baiyue.lastleg.delivery.mapper.OutboundOrderMapper;
|
||||
@@ -40,6 +41,7 @@ import com.baiyue.lastleg.inventory.mapper.InventoryBalanceMapper;
|
||||
import com.baiyue.lastleg.inventory.mapper.InventoryPositionMapper;
|
||||
import com.baiyue.lastleg.dropship.entity.DropshipOrderProfile;
|
||||
import com.baiyue.lastleg.dropship.entity.DropshipCarton;
|
||||
import com.baiyue.lastleg.dropship.model.DropshipOutboundCandidate;
|
||||
import com.baiyue.lastleg.dropship.mapper.DropshipOrderProfileMapper;
|
||||
import com.baiyue.lastleg.dropship.mapper.DropshipCartonMapper;
|
||||
import com.baiyue.lastleg.dropship.mapper.DropshipSkuInventoryMapper;
|
||||
@@ -116,6 +118,7 @@ public class DeliveryTransferService {
|
||||
if (Set.of("CANCELLED", "DEPARTED", "PARTIAL_DEPARTED", "COMPLETED").contains(dispatch.getStatus())) {
|
||||
throw conflict("Dispatch cannot be transferred to delivery in its current status");
|
||||
}
|
||||
dispatchItems.bindReceivedPallets(customerId, dispatch.getId());
|
||||
List<DispatchItem> items = dispatchItems.findByDispatchOrder(customerId, dispatch.getId());
|
||||
if (items.isEmpty()) throw conflict("Dispatch has no pallets");
|
||||
if (items.stream().anyMatch(item -> item.getWarehousePalletId() == null)) {
|
||||
@@ -130,7 +133,7 @@ public class DeliveryTransferService {
|
||||
outbound.setOutboundNo(orderNoGenerator.next("OUTBOUND", dispatch.getOverseasWarehouseId(), outbound.getId()));
|
||||
outbound.setDispatchOrderId(dispatch.getId()); outbound.setDispatchNo(dispatch.getDispatchNo());
|
||||
outbound.setOverseasWarehouseId(dispatch.getOverseasWarehouseId()); outbound.setStatus("WAIT_OUTBOUND"); outbound.setOutboundType("DISPATCH_DELIVERY");
|
||||
outbound.setLxCodes(items.stream().map(DispatchItem::getInboundCode).filter(StringUtils::hasText).map(code -> tailOrders.selectOne(new LambdaQueryWrapper<LastlegOrder>().eq(LastlegOrder::getCustomerId, customerId).eq(LastlegOrder::getInboundCode, code))).filter(Objects::nonNull).map(LastlegOrder::getLxCode).filter(StringUtils::hasText).distinct().collect(java.util.stream.Collectors.joining(",")));
|
||||
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.setCreatedBy(operatorId); outbound.setCreatedAt(now); outbound.setUpdatedAt(now);
|
||||
@@ -178,7 +181,7 @@ public class DeliveryTransferService {
|
||||
delivery.setDispatchOrderId(dispatch.getId()); delivery.setDispatchNo(dispatch.getDispatchNo());
|
||||
delivery.setOverseasWarehouseId(dispatch.getOverseasWarehouseId()); delivery.setOverseasWarehouseName(dispatch.getOverseasWarehouseName());
|
||||
LastlegOrder firstOrder = firstTailOrder(customerId, items);
|
||||
delivery.setCustomerName(firstOrder == null ? null : firstOrder.getCustomerName()); delivery.setStatus("WAIT_DELIVERY");
|
||||
delivery.setCustomerName(firstOrder == null ? null : firstOrder.getCustomerName()); delivery.setStatus("WAIT_DELIVERY"); delivery.setVersion(0L);
|
||||
delivery.setWaybillNo(trim(request.waybillNo())); delivery.setDeliveryMethod(request.deliveryMethod().trim());
|
||||
delivery.setCarrierName(firstText(request.carrierName(), dispatch.getCarrierName())); delivery.setPickupMethod(trim(request.pickupMethod()));
|
||||
delivery.setLoadingType(trim(request.loadingType())); delivery.setVehicleType(trim(request.vehicleType())); delivery.setVehicleSize(trim(request.vehicleSize()));
|
||||
@@ -250,30 +253,35 @@ public class DeliveryTransferService {
|
||||
return taskResult(outbound, task);
|
||||
}
|
||||
|
||||
public List<DeliveryResponses.OneClickCandidate> oneClickCandidates(String customerId, String warehouseId) {
|
||||
return dropshipProfiles.listOutboundCandidates(required(customerId, "Customer is required"),
|
||||
StringUtils.hasText(warehouseId) ? warehouseId.trim() : null).stream()
|
||||
.map(this::oneClickCandidate).toList();
|
||||
}
|
||||
|
||||
private String validateOneClickItems(String customerId, List<DeliveryRequests.OneClickItem> items) {
|
||||
String warehouseId = null;
|
||||
Map<String, Long> requestedPackages = new LinkedHashMap<>();
|
||||
Map<String, DropshipOrderProfile> profiles = new HashMap<>();
|
||||
Map<String, DropshipOutboundCandidate> candidates = new HashMap<>();
|
||||
for (DeliveryRequests.OneClickItem input : items) {
|
||||
InventoryPosition position = inventoryPositions.selectById(input.inventoryPositionId());
|
||||
if (position == null || !customerId.equals(position.getCustomerId())) throw notFound("Inventory position not found");
|
||||
DropshipOrderProfile profile = dropshipProfiles.findPosition(customerId, position.getId());
|
||||
if (profile == null) throw conflict("Selected pallet is not one-click dropship inventory");
|
||||
if (warehouseId == null) warehouseId = position.getOverseasWarehouseId();
|
||||
else if (!Objects.equals(warehouseId, position.getOverseasWarehouseId())) {
|
||||
throw conflict("One outbound order must use inventory from the same overseas warehouse");
|
||||
String sku = input.sku().trim();
|
||||
DropshipOutboundCandidate candidate = dropshipProfiles.lockOutboundCandidate(customerId,
|
||||
input.inventoryPositionId(), sku);
|
||||
if (candidate == null) {
|
||||
throw conflict("所选库存不是可用的一件代发库存,或已被其他作业占用");
|
||||
}
|
||||
if (value(position.getAvailablePackages()) < input.packages()) {
|
||||
throw conflict("Insufficient available inventory for pallet " + position.getPalletNo());
|
||||
if (warehouseId == null) warehouseId = candidate.getOverseasWarehouseId();
|
||||
else if (!Objects.equals(warehouseId, candidate.getOverseasWarehouseId())) {
|
||||
throw conflict("一张出库单只能选择同一海外仓的库存");
|
||||
}
|
||||
String key = profile.getId() + "\u0000" + input.sku().trim();
|
||||
String key = candidate.getProfileId() + "\u0000" + sku;
|
||||
requestedPackages.merge(key, input.packages(), Long::sum);
|
||||
profiles.put(key, profile);
|
||||
candidates.put(key, candidate);
|
||||
if (input.cartonMarks() != null && !input.cartonMarks().isEmpty()) {
|
||||
if (input.cartonMarks().size() != input.packages() || new HashSet<>(input.cartonMarks()).size() != input.cartonMarks().size()) {
|
||||
throw conflict("Specified carton marks must be unique and equal the package count");
|
||||
}
|
||||
List<DropshipCarton> selected = dropshipCartons.listProfile(customerId, profile.getId()).stream()
|
||||
List<DropshipCarton> selected = dropshipCartons.listProfile(customerId, candidate.getProfileId()).stream()
|
||||
.filter(carton -> "AVAILABLE".equals(carton.getStatus()) && input.sku().trim().equals(carton.getSkuCode())
|
||||
&& input.cartonMarks().contains(carton.getCartonMark())).toList();
|
||||
if (selected.size() != input.cartonMarks().size()) throw conflict("Specified carton marks are unavailable");
|
||||
@@ -281,10 +289,14 @@ public class DeliveryTransferService {
|
||||
}
|
||||
for (Map.Entry<String, Long> requested : requestedPackages.entrySet()) {
|
||||
String sku = requested.getKey().substring(requested.getKey().indexOf('\u0000') + 1);
|
||||
DropshipOutboundCandidate candidate = candidates.get(requested.getKey());
|
||||
if (requested.getValue() > value(candidate.getAvailablePackages())) {
|
||||
throw conflict("一件代发可用箱数不足:" + candidate.getPalletNo() + " / " + sku);
|
||||
}
|
||||
List<DropshipCarton> cartons = dropshipCartons.lockAvailable(customerId,
|
||||
profiles.get(requested.getKey()).getId(), sku, requested.getValue());
|
||||
candidate.getProfileId(), sku, requested.getValue());
|
||||
if (cartons.size() != requested.getValue()) {
|
||||
throw conflict("Insufficient available one-click dropship cartons for SKU " + sku);
|
||||
throw conflict("一件代发可用箱数不足:" + candidate.getPalletNo() + " / " + sku);
|
||||
}
|
||||
}
|
||||
return warehouseId;
|
||||
@@ -399,7 +411,7 @@ public class DeliveryTransferService {
|
||||
throw conflict("Outbound order cannot be cancelled while delivery is in progress");
|
||||
LocalDateTime now = LocalDateTime.now();
|
||||
DeliveryOrder delivery = existingDelivery;
|
||||
if (delivery != null) { delivery.setStatus("CANCELLED"); delivery.setUpdatedAt(now); deliveryOrders.updateById(delivery); }
|
||||
if (delivery != null) { delivery.setStatus("CANCELLED"); delivery.setVersion(value(delivery.getVersion()) + 1); delivery.setUpdatedAt(now); deliveryOrders.updateById(delivery); }
|
||||
OutboundPdaTask task = pdaTasks.lockByOutbound(customerId, outbound.getId());
|
||||
if (task != null) { task.setStatus("CANCELLED"); task.setUpdatedAt(now); pdaTasks.updateById(task); }
|
||||
outbound.setStatus("CANCELLED"); outbound.setUpdatedAt(now); outboundOrders.updateById(outbound);
|
||||
@@ -432,6 +444,36 @@ public class DeliveryTransferService {
|
||||
return new DeliveryResponses.PdaTaskDetail(taskResult(outbound, task), items);
|
||||
}
|
||||
|
||||
public DeliveryResponses.PdaTaskResolution resolvePdaTask(String warehouseId, String businessNo) {
|
||||
String boundWarehouseId = required(warehouseId, "PDA warehouse binding is required");
|
||||
String code = required(businessNo, "Outbound task, outbound or dispatch number is required");
|
||||
|
||||
OutboundPdaTask task = pdaTasks.findByNoAndWarehouse(code, boundWarehouseId);
|
||||
if (task != null) {
|
||||
OutboundOrder outbound = requireOutboundInWarehouse(task, boundWarehouseId);
|
||||
return outboundResolution(outbound, task);
|
||||
}
|
||||
|
||||
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());
|
||||
if (dispatch != null && boundWarehouseId.equals(dispatch.getOverseasWarehouseId())) {
|
||||
return new DeliveryResponses.PdaTaskResolution("DISPATCH", null, outbound.getOutboundNo(),
|
||||
dispatch.getDispatchNo());
|
||||
}
|
||||
}
|
||||
task = pdaTasks.findByOutboundAndWarehouse(outbound.getCustomerId(), outbound.getId(), boundWarehouseId);
|
||||
if (task != null) return outboundResolution(outbound, task);
|
||||
}
|
||||
|
||||
DispatchOrder dispatch = dispatchOrders.findGlobalByDispatchNo(code);
|
||||
if (dispatch != null && boundWarehouseId.equals(dispatch.getOverseasWarehouseId())) {
|
||||
return new DeliveryResponses.PdaTaskResolution("DISPATCH", null, null, dispatch.getDispatchNo());
|
||||
}
|
||||
throw notFound("Outbound or dispatch task not found in the bound warehouse");
|
||||
}
|
||||
|
||||
private List<DeliveryResponses.PdaPickPosition> pdaPickPositions(String customerId, String warehouseId,
|
||||
OutboundPalletItem item) {
|
||||
if (item.getWarehousePalletId() == null) return List.of();
|
||||
@@ -471,6 +513,10 @@ public class DeliveryTransferService {
|
||||
}
|
||||
|
||||
private DeliveryResponses.PdaTask taskResult(OutboundOrder outbound, OutboundPdaTask task) { return new DeliveryResponses.PdaTask(task.getId(), task.getTaskNo(), task.getStatus(), outbound.getOutboundNo(), task.getPushedAt(), task.getCompletedAt()); }
|
||||
private DeliveryResponses.PdaTaskResolution outboundResolution(OutboundOrder outbound, OutboundPdaTask task) {
|
||||
return new DeliveryResponses.PdaTaskResolution("OUTBOUND", task.getTaskNo(), outbound.getOutboundNo(),
|
||||
outbound.getDispatchNo());
|
||||
}
|
||||
private OutboundOrder requireOutbound(OutboundPdaTask task) {
|
||||
OutboundOrder outbound = outboundOrders.selectById(task.getOutboundOrderId());
|
||||
if (outbound == null || !task.getCustomerId().equals(outbound.getCustomerId())) {
|
||||
@@ -499,14 +545,13 @@ public class DeliveryTransferService {
|
||||
return page(page, page.getRecords().stream().map(this::outboundRow).toList());
|
||||
}
|
||||
|
||||
public DeliveryResponses.OutboundDetail outboundDetail(String outboundNo,
|
||||
DeliveryRequests.PalletQuery query) {
|
||||
public DeliveryResponses.OutboundDetail outboundDetail(String outboundNo) {
|
||||
OutboundOrder outbound = outboundOrders.findGlobalByNo(trim(outboundNo));
|
||||
if (outbound == null) throw notFound("Outbound order not found");
|
||||
String customerId = outbound.getCustomerId();
|
||||
DeliveryOrder delivery = requireDelivery(customerId, outbound.getId());
|
||||
List<DeliveryResponses.OutboundPalletRow> pallets = outboundPallets.findByOutbound(customerId, outbound.getId()).stream()
|
||||
.map(item -> new DeliveryResponses.OutboundPalletRow(item.getId(), item.getPalletNo(), item.getCartonMarks(), item.getSkuCode(), item.getInboundCode(), item.getPackageCount(), item.getPickedPackageCount(), item.getStatus())).toList();
|
||||
.map(this::outboundPalletRow).toList();
|
||||
return new DeliveryResponses.OutboundDetail(outboundRow(outbound), deliveryRow(delivery), pallets);
|
||||
}
|
||||
|
||||
@@ -582,12 +627,33 @@ public class DeliveryTransferService {
|
||||
d.getDeliveryNo(), d.getStatus(), o.getPalletCount(), o.getPackageCount(), 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()); }
|
||||
private DeliveryResponses.DeliveryRow deliveryRow(DeliveryOrder d) { return new DeliveryResponses.DeliveryRow(d.getId(), d.getCustomerId(), d.getCustomerName(), d.getDeliveryNo(), d.getOutboundNo(), d.getDispatchNo(), d.getOverseasWarehouseId(), d.getOverseasWarehouseName(), d.getStatus(), d.getWaybillNo(), d.getDeliveryMethod(), d.getCarrierName(), d.getPickupMethod(), d.getLoadingType(), d.getVehicleType(), d.getVehicleSize(), d.getVehiclePlate(), d.getDriverName(), d.getDriverPhone(), d.getAppointmentAccount(), d.getSellerName(), value(d.getPalletCount()), value(d.getPackageCount()), d.getTotalWeightKg(), d.getTotalVolumeCbm(), d.getPlannedDeliveryAt(), d.getDispatchedAt(), d.getExpectedArrivalAt(), d.getSignedAt(), d.getRemark(), d.getCreatedAt()); }
|
||||
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());
|
||||
}
|
||||
private DeliveryResponses.OneClickCandidate oneClickCandidate(DropshipOutboundCandidate candidate) {
|
||||
return new DeliveryResponses.OneClickCandidate(candidate.getInventoryPositionId(),
|
||||
candidate.getOverseasWarehouseId(), candidate.getOverseasWarehouseName(), candidate.getPalletNo(),
|
||||
candidate.getInboundCode(), candidate.getSkuCode(), candidate.getProductName(),
|
||||
value(candidate.getAvailablePackages()));
|
||||
}
|
||||
private DeliveryResponses.DeliveryRow deliveryRow(DeliveryOrder d) { return new DeliveryResponses.DeliveryRow(d.getId(), d.getCustomerId(), d.getCustomerName(), d.getDeliveryNo(), d.getOutboundNo(), d.getDispatchNo(), d.getOverseasWarehouseId(), d.getOverseasWarehouseName(), d.getStatus(), d.getWaybillNo(), d.getDeliveryMethod(), d.getCarrierName(), d.getPickupMethod(), d.getLoadingType(), d.getVehicleType(), d.getVehicleSize(), d.getVehiclePlate(), d.getDriverName(), d.getDriverPhone(), d.getAppointmentAccount(), d.getSellerName(), value(d.getPalletCount()), value(d.getPackageCount()), d.getTotalWeightKg(), d.getTotalVolumeCbm(), d.getPlannedDeliveryAt(), d.getDispatchedAt(), d.getExpectedArrivalAt(), d.getSignedAt(), d.getRemark(), d.getCreatedAt(), value(d.getVersion()), DeliveryStatusPolicy.allowedActions(d.getStatus())); }
|
||||
private DeliveryResponses.DeliverySku sku(LastlegOrderDetail d, LastlegOrder order) { return new DeliveryResponses.DeliverySku(order == null ? null : order.getInboundCode(), order == null ? null : order.getCustomerName(), d.getDestinationWarehouseCode(), null, d.getShipmentNo(), d.getFbaTrackingNo(), d.getSkuCode(), firstText(d.getProductNameZh(), d.getProductNameEn()), value(d.getPackageCount()), d.getGrossWeightKg(), d.getVolumeCbm()); }
|
||||
private DeliveryResponses.DeliveryFeeRow feeRow(DeliveryFee f) { return new DeliveryResponses.DeliveryFeeRow(f.getId(), f.getFeeDirection(), f.getFeeType(), f.getCurrency(), f.getAmount(), f.getRemark()); }
|
||||
private DeliveryResponses.DeliveryOperationRow operationRow(DeliveryOperation o) { return new DeliveryResponses.DeliveryOperationRow(o.getId(), o.getCreatedAt(), o.getOperationNode(), firstText(o.getOperatorName(), o.getOperatorId()), o.getResult()); }
|
||||
private void recordOperation(String customerId, Long deliveryId, String operatorId, String node, String result, LocalDateTime now) { DeliveryOperation operation = new DeliveryOperation(); operation.setCustomerId(customerId); operation.setDeliveryOrderId(deliveryId); operation.setOperationNode(node); operation.setOperatorId(operatorId); operation.setOperatorName(operatorId); operation.setResult(result); operation.setCreatedAt(now); deliveryOperations.insert(operation); }
|
||||
private LastlegOrder firstTailOrder(String customerId, List<DispatchItem> items) { return items.stream().map(DispatchItem::getOrderId).filter(Objects::nonNull).map(tailOrders::selectById).filter(Objects::nonNull).filter(order -> customerId.equals(order.getCustomerId())).findFirst().orElse(null); }
|
||||
private String resolveLxCodes(String customerId, List<DispatchItem> items) {
|
||||
List<String> inboundCodes = items.stream().map(DispatchItem::getInboundCode)
|
||||
.filter(StringUtils::hasText).map(String::trim).distinct().toList();
|
||||
if (inboundCodes.isEmpty()) return "";
|
||||
return tailOrders.selectList(new LambdaQueryWrapper<LastlegOrder>()
|
||||
.eq(LastlegOrder::getCustomerId, customerId)
|
||||
.in(LastlegOrder::getInboundCode, inboundCodes))
|
||||
.stream().map(LastlegOrder::getLxCode).filter(StringUtils::hasText)
|
||||
.map(String::trim).distinct().collect(java.util.stream.Collectors.joining(","));
|
||||
}
|
||||
private BigDecimal totalWeight(String customerId, List<DispatchItem> items) { List<Long> ids = items.stream().map(DispatchItem::getOrderId).filter(Objects::nonNull).distinct().toList(); if (ids.isEmpty()) return BigDecimal.ZERO; return tailOrderDetails.selectList(new LambdaQueryWrapper<LastlegOrderDetail>().eq(LastlegOrderDetail::getCustomerId, customerId).in(LastlegOrderDetail::getOrderId, ids)).stream().map(LastlegOrderDetail::getGrossWeightKg).filter(Objects::nonNull).reduce(BigDecimal.ZERO, BigDecimal::add); }
|
||||
private static String trim(String value) { return StringUtils.hasText(value) ? value.trim() : null; }
|
||||
private static String required(String value, String message) {
|
||||
|
||||
Reference in New Issue
Block a user