优化提交
This commit is contained in:
+7
@@ -36,6 +36,13 @@ public class MerchantWarehouseTransferController {
|
||||
return ApiResponse.success(service.detail(customer(user), transferNo));
|
||||
}
|
||||
|
||||
@PostMapping("/{transferNo}/confirm-measurement")
|
||||
public ApiResponse<WarehouseTransferResponses.Detail> confirmMeasurement(
|
||||
@AuthenticationPrincipal AuthenticatedUser user, @PathVariable String transferNo,
|
||||
@Valid @RequestBody WarehouseTransferRequests.CustomerConfirm request) {
|
||||
return ApiResponse.success(service.confirmMeasurement(customer(user), transferNo, operator(user), request));
|
||||
}
|
||||
|
||||
private String customer(AuthenticatedUser user) {
|
||||
if (user == null || user.tenantId() == null) throw new ResponseStatusException(HttpStatus.UNAUTHORIZED);
|
||||
if ("PLATFORM".equals(user.appCode()) || user.tenantId() == 0L) {
|
||||
|
||||
+43
@@ -0,0 +1,43 @@
|
||||
package com.baiyue.lastleg.transfer.controller;
|
||||
|
||||
import com.baiyue.common.core.api.ApiResponse;
|
||||
import com.baiyue.common.security.AuthenticatedUser;
|
||||
import com.baiyue.lastleg.pda.security.PdaWarehouseIdentity;
|
||||
import com.baiyue.lastleg.transfer.dto.WarehouseTransferRequests;
|
||||
import com.baiyue.lastleg.transfer.dto.WarehouseTransferResponses;
|
||||
import com.baiyue.lastleg.transfer.service.WarehouseTransferService;
|
||||
import jakarta.annotation.Resource;
|
||||
import jakarta.validation.Valid;
|
||||
import org.springframework.security.access.prepost.PreAuthorize;
|
||||
import org.springframework.security.core.annotation.AuthenticationPrincipal;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.PathVariable;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.bind.annotation.RequestBody;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@RestController
|
||||
@RequestMapping("/api/pda/v1/last-leg/warehouse-transfers")
|
||||
@PreAuthorize("hasAuthority('lastleg:pda:operate') and hasAuthority('ROLE_OVERSEAS_WAREHOUSE_PDA_OPERATOR')")
|
||||
public class PdaWarehouseTransferController {
|
||||
@Resource private WarehouseTransferService service;
|
||||
|
||||
@GetMapping("/candidates")
|
||||
public ApiResponse<List<WarehouseTransferResponses.Summary>> candidates(
|
||||
@AuthenticationPrincipal AuthenticatedUser user) {
|
||||
PdaWarehouseIdentity identity = PdaWarehouseIdentity.require(user);
|
||||
return ApiResponse.success(service.pdaCandidates(identity.overseasWarehouseId()));
|
||||
}
|
||||
|
||||
@PostMapping("/{transferNo}/palletize")
|
||||
public ApiResponse<WarehouseTransferResponses.Detail> palletize(
|
||||
@AuthenticationPrincipal AuthenticatedUser user, @PathVariable String transferNo,
|
||||
@Valid @RequestBody WarehouseTransferRequests.Palletize request) {
|
||||
PdaWarehouseIdentity identity = PdaWarehouseIdentity.require(user);
|
||||
return ApiResponse.success(service.palletize(identity.operatorKey(), identity.overseasWarehouseId(),
|
||||
transferNo, request));
|
||||
}
|
||||
}
|
||||
+12
-8
@@ -3,12 +3,14 @@ package com.baiyue.lastleg.transfer.controller;
|
||||
import com.baiyue.common.core.api.ApiResponse;
|
||||
import com.baiyue.common.core.api.PageResult;
|
||||
import com.baiyue.common.security.AuthenticatedUser;
|
||||
import com.baiyue.lastleg.security.OverseasPermissions;
|
||||
import com.baiyue.lastleg.transfer.dto.WarehouseTransferRequests;
|
||||
import com.baiyue.lastleg.transfer.dto.WarehouseTransferResponses;
|
||||
import com.baiyue.lastleg.transfer.service.WarehouseTransferService;
|
||||
import jakarta.annotation.Resource;
|
||||
import jakarta.validation.Valid;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.security.access.prepost.PreAuthorize;
|
||||
import org.springframework.security.core.annotation.AuthenticationPrincipal;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
import org.springframework.web.server.ResponseStatusException;
|
||||
@@ -26,22 +28,31 @@ public class WarehouseTransferController {
|
||||
}
|
||||
|
||||
@GetMapping
|
||||
@PreAuthorize("hasAuthority('" + OverseasPermissions.LAST_MILE_ORDER_LIST + "')")
|
||||
public ApiResponse<PageResult<WarehouseTransferResponses.Summary>> page(@AuthenticationPrincipal AuthenticatedUser user,
|
||||
@RequestParam(required = false) String customerId, @Valid WarehouseTransferRequests.Query query) {
|
||||
return ApiResponse.success(service.page(scope(user, customerId), query));
|
||||
}
|
||||
|
||||
@GetMapping("/{transferNo}")
|
||||
@PreAuthorize("hasAuthority('" + OverseasPermissions.LAST_MILE_ORDER_LIST + "')")
|
||||
public ApiResponse<WarehouseTransferResponses.Detail> detail(@AuthenticationPrincipal AuthenticatedUser user,
|
||||
@RequestParam(required = false) String customerId, @PathVariable String transferNo) {
|
||||
return ApiResponse.success(service.detail(scope(user, customerId), transferNo));
|
||||
}
|
||||
|
||||
@GetMapping("/{transferNo}/carton-label")
|
||||
@PreAuthorize("hasAuthority('" + OverseasPermissions.LAST_MILE_ORDER_LIST + "')")
|
||||
public ApiResponse<WarehouseTransferResponses.Label> cartonLabel(@AuthenticationPrincipal AuthenticatedUser user,
|
||||
@RequestParam(required = false) String customerId, @PathVariable String transferNo) {
|
||||
return ApiResponse.success(service.cartonLabel(scope(user, customerId), transferNo));
|
||||
}
|
||||
|
||||
@PostMapping("/{transferNo}/review")
|
||||
@PreAuthorize("hasAuthority('" + OverseasPermissions.WAREHOUSE_TRANSFER_APPROVE + "')")
|
||||
public ApiResponse<WarehouseTransferResponses.Detail> review(@AuthenticationPrincipal AuthenticatedUser user,
|
||||
@RequestParam(required = false) String customerId, @PathVariable String transferNo,
|
||||
@Valid @RequestBody WarehouseTransferRequests.Review request) {
|
||||
requireApprovalPermission(user);
|
||||
return ApiResponse.success(service.review(scope(user, customerId), transferNo, operator(user), request));
|
||||
}
|
||||
|
||||
@@ -69,13 +80,6 @@ public class WarehouseTransferController {
|
||||
return ApiResponse.success(service.receive(scope(user, customerId), transferNo, operator(user), request));
|
||||
}
|
||||
|
||||
private void requireApprovalPermission(AuthenticatedUser user) {
|
||||
if (user == null || user.permissions() == null
|
||||
|| !user.permissions().contains("lastleg:warehouse-transfer:approve")) {
|
||||
throw new ResponseStatusException(HttpStatus.FORBIDDEN, "Warehouse transfer approval permission is required");
|
||||
}
|
||||
}
|
||||
|
||||
private void requirePermission(AuthenticatedUser user, String permission) {
|
||||
if (user == null || user.tenantId() == null) throw new ResponseStatusException(HttpStatus.UNAUTHORIZED);
|
||||
if (user.permissions() == null || !user.permissions().contains(permission)) {
|
||||
|
||||
+49
-3
@@ -23,17 +23,34 @@ public final class WarehouseTransferRequests {
|
||||
@Size(max = 128) String fbaWarehouseCode,
|
||||
@NotBlank @Size(max = 1000) String deliveryAddress,
|
||||
@Positive int packageCount,
|
||||
@NotNull @DecimalMin(value = "0.0001") BigDecimal volumeCbm,
|
||||
@NotNull @DecimalMin(value = "0.0") BigDecimal volumeCbm,
|
||||
@NotBlank @Size(max = 64) String deliveryMethod,
|
||||
@NotNull LocalDateTime estimatedArrivalAt,
|
||||
LocalDateTime estimatedShipAt,
|
||||
@Size(max = 128) String fbaShipmentNo,
|
||||
@Size(max = 255) String trackingNo,
|
||||
@Size(max = 2000) String fbaBoxNos,
|
||||
@Size(max = 1000) String remark,
|
||||
boolean needRelabel,
|
||||
LocalDateTime labelDeadline,
|
||||
@Size(max = 128) String relabelContactName,
|
||||
@Size(max = 64) String relabelContactPhone,
|
||||
@DecimalMin(value = "0.01") BigDecimal relabelChargeAmount,
|
||||
@Size(max = 32) String relabelDeliveryMethod,
|
||||
@NotBlank @Size(max = 255) String idempotencyKey,
|
||||
@NotEmpty @Size(max = 500) List<@Valid Item> items
|
||||
) {}
|
||||
@NotEmpty @Size(max = 500) List<@Valid Item> items,
|
||||
@Size(max = 1000) List<@Valid RelabelItem> relabelItems
|
||||
) {
|
||||
public Create(String inboundCode, List<Long> sourceLastlegOrderIds, String operatingWarehouseId,
|
||||
String fbaWarehouseCode, String deliveryAddress, int packageCount, BigDecimal volumeCbm,
|
||||
String deliveryMethod, LocalDateTime estimatedArrivalAt, String fbaShipmentNo,
|
||||
String trackingNo, String fbaBoxNos, String remark, boolean needRelabel,
|
||||
String idempotencyKey, List<Item> items) {
|
||||
this(inboundCode, sourceLastlegOrderIds, operatingWarehouseId, fbaWarehouseCode, deliveryAddress,
|
||||
packageCount, volumeCbm, deliveryMethod, estimatedArrivalAt, null, fbaShipmentNo, trackingNo,
|
||||
fbaBoxNos, remark, needRelabel, null, null, null, null, null, idempotencyKey, items, null);
|
||||
}
|
||||
}
|
||||
|
||||
public record Review(@NotBlank @Size(max = 32) String decision,
|
||||
@Size(max = 1000) String remark) {}
|
||||
@@ -52,6 +69,24 @@ public final class WarehouseTransferRequests {
|
||||
public record Outbound(@NotBlank @Size(max = 255) String idempotencyKey,
|
||||
@Size(max = 1000) String remark) {}
|
||||
|
||||
public record Palletize(
|
||||
@NotBlank @Size(max = 255) String idempotencyKey,
|
||||
@NotEmpty @Size(max = 100) List<@Valid Pallet> pallets
|
||||
) {}
|
||||
|
||||
public record Pallet(
|
||||
@Size(max = 128) String palletCode,
|
||||
@Positive int cartonCount,
|
||||
@NotNull @DecimalMin("0.000001") BigDecimal volumeCbm,
|
||||
@NotNull @DecimalMin("0.01") BigDecimal grossWeightKg,
|
||||
@NotEmpty @Size(max = 500) List<@Valid PalletItem> items
|
||||
) {}
|
||||
|
||||
public record PalletItem(@NotNull Long transferItemId, @Positive int packageCount) {}
|
||||
|
||||
public record CustomerConfirm(@NotBlank @Size(max = 255) String idempotencyKey,
|
||||
@Size(max = 1000) String remark) {}
|
||||
|
||||
public record Receipt(
|
||||
@NotNull Long sourceInventoryPositionId,
|
||||
@NotBlank @Size(max = 128) String destinationOverseasWarehouseId,
|
||||
@@ -76,6 +111,17 @@ public final class WarehouseTransferRequests {
|
||||
@Size(max = 255) String shippingMark
|
||||
) {}
|
||||
|
||||
public record RelabelItem(
|
||||
@NotBlank @Size(max = 32) String operationType,
|
||||
@NotEmpty @Size(max = 500) List<@NotBlank @Size(max = 255) String> customerCartonMarks,
|
||||
@NotBlank @Size(max = 128) String originalSku,
|
||||
@Size(max = 128) String newSku,
|
||||
@Positive int quantity,
|
||||
@Size(max = 255) String fbaCartonMark,
|
||||
@Size(max = 128) String destinationWarehouseCode,
|
||||
@Size(max = 1000) String remark
|
||||
) {}
|
||||
|
||||
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,
|
||||
|
||||
+19
-5
@@ -1,12 +1,23 @@
|
||||
package com.baiyue.lastleg.transfer.dto;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.List;
|
||||
|
||||
public final class WarehouseTransferResponses {
|
||||
private WarehouseTransferResponses() {}
|
||||
public record Item(String skuCode, String productNameZh, int packageCount, String shippingMark) {}
|
||||
public record Carton(String cartonMark, int cartonIndex, int totalCartons, String status) {}
|
||||
public record Item(Long id, String skuCode, String productNameZh, int packageCount, String shippingMark) {}
|
||||
public record Carton(String cartonMark, String customerCartonMark, int cartonIndex, int totalCartons, String status) {}
|
||||
public record Label(String transferNo, List<Carton> cartons, String printableHtml) {}
|
||||
public record PalletItem(Long transferItemId, String skuCode, int packageCount) {}
|
||||
public record Pallet(Long id, int sequenceNo, Long warehousePalletId, String palletNo,
|
||||
Long warehouseLocationId, String warehouseLocationCode, int cartonCount,
|
||||
BigDecimal lengthCm, BigDecimal widthCm, BigDecimal heightCm,
|
||||
BigDecimal grossWeightKg, BigDecimal volumeCbm, String status,
|
||||
List<PalletItem> items, LocalDateTime completedAt) {}
|
||||
public record RelabelBinding(String operationType, String customerCartonMark, String originalSku,
|
||||
String newSku, int quantity, String fbaCartonMark,
|
||||
String destinationWarehouseCode, String remark) {}
|
||||
public record SourceOrder(Long lastlegOrderId, String lastlegOrderNo, Long inboundOrderId, String inboundCode) {}
|
||||
public record Allocation(Long inventoryPositionId, Long inboundOrderId, String inboundCode,
|
||||
Long palletId, String palletNo, int packageCount, String status,
|
||||
@@ -19,9 +30,12 @@ public final class WarehouseTransferResponses {
|
||||
Long lastlegOrderId, String lastlegOrderNo, String orderType, String orderStatus,
|
||||
String status,
|
||||
boolean needRelabel, Long relabelApplicationId, String relabelNo, String relabelStatus,
|
||||
String operatingWarehouseId, String fbaWarehouseCode, String deliveryAddress,
|
||||
String operatingWarehouseId, String fbaWarehouseCode, String deliveryAddress,
|
||||
int packageCount, String deliveryMethod, LocalDateTime estimatedArrivalAt,
|
||||
LocalDateTime estimatedShipAt,
|
||||
String fbaShipmentNo, String trackingNo, String fbaBoxNos, String remark,
|
||||
List<SourceOrder> sourceOrders, List<Item> items, List<Carton> cartons, List<Allocation> allocations,
|
||||
LocalDateTime outboundAt, LocalDateTime createdAt) {}
|
||||
List<SourceOrder> sourceOrders, List<Item> items, List<Carton> cartons,
|
||||
List<Pallet> pallets, List<RelabelBinding> relabelBindings,
|
||||
List<Allocation> allocations, LocalDateTime customerConfirmedAt,
|
||||
LocalDateTime actualShipAt, LocalDateTime createdAt) {}
|
||||
}
|
||||
|
||||
+1
@@ -15,6 +15,7 @@ public class WarehouseTransferCarton {
|
||||
private Long transferItemId;
|
||||
private String customerId;
|
||||
private String cartonMark;
|
||||
private String customerCartonMark;
|
||||
private Integer cartonIndex;
|
||||
private Integer totalCartons;
|
||||
private String status;
|
||||
|
||||
+12
@@ -22,19 +22,31 @@ public class WarehouseTransferOrder {
|
||||
private Integer packageCount;
|
||||
private String deliveryMethod;
|
||||
private LocalDateTime estimatedArrivalAt;
|
||||
private LocalDateTime estimatedShipAt;
|
||||
private String fbaShipmentNo;
|
||||
private String trackingNo;
|
||||
private String fbaBoxNos;
|
||||
private String remark;
|
||||
private Boolean needRelabel;
|
||||
private LocalDateTime labelDeadline;
|
||||
private String relabelContactName;
|
||||
private String relabelContactPhone;
|
||||
private java.math.BigDecimal relabelChargeAmount;
|
||||
private String relabelDeliveryMethod;
|
||||
private Long relabelApplicationId;
|
||||
private String relabelNo;
|
||||
private LocalDateTime relabelCompletedAt;
|
||||
private String status;
|
||||
private String allocationIdempotencyKey;
|
||||
private String allocationRequestHash;
|
||||
private String outboundIdempotencyKey;
|
||||
private String outboundRequestHash;
|
||||
private LocalDateTime outboundAt;
|
||||
private String palletizeIdempotencyKey;
|
||||
private String palletizeRequestHash;
|
||||
private String confirmationIdempotencyKey;
|
||||
private String confirmationRequestHash;
|
||||
private LocalDateTime customerConfirmedAt;
|
||||
private String idempotencyKey;
|
||||
private String requestHash;
|
||||
private String createdBy;
|
||||
|
||||
+33
@@ -0,0 +1,33 @@
|
||||
package com.baiyue.lastleg.transfer.entity;
|
||||
|
||||
import com.baomidou.mybatisplus.annotation.IdType;
|
||||
import com.baomidou.mybatisplus.annotation.TableId;
|
||||
import com.baomidou.mybatisplus.annotation.TableName;
|
||||
import lombok.Data;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
@Data
|
||||
@TableName("ll_warehouse_transfer_pallet")
|
||||
public class WarehouseTransferPallet {
|
||||
@TableId(type = IdType.INPUT) private Long id;
|
||||
private Long transferOrderId;
|
||||
private String customerId;
|
||||
private Integer sequenceNo;
|
||||
private Long warehousePalletId;
|
||||
private String palletNo;
|
||||
private Long warehouseLocationId;
|
||||
private String warehouseLocationCode;
|
||||
private Long warehouseResourceLockId;
|
||||
private Integer cartonCount;
|
||||
private BigDecimal lengthCm;
|
||||
private BigDecimal widthCm;
|
||||
private BigDecimal heightCm;
|
||||
private BigDecimal grossWeightKg;
|
||||
private BigDecimal volumeCbm;
|
||||
private String status;
|
||||
private LocalDateTime completedAt;
|
||||
private LocalDateTime createdAt;
|
||||
private LocalDateTime updatedAt;
|
||||
}
|
||||
+20
@@ -0,0 +1,20 @@
|
||||
package com.baiyue.lastleg.transfer.entity;
|
||||
|
||||
import com.baomidou.mybatisplus.annotation.IdType;
|
||||
import com.baomidou.mybatisplus.annotation.TableId;
|
||||
import com.baomidou.mybatisplus.annotation.TableName;
|
||||
import lombok.Data;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
@Data
|
||||
@TableName("ll_warehouse_transfer_pallet_item")
|
||||
public class WarehouseTransferPalletItem {
|
||||
@TableId(type = IdType.INPUT) private Long id;
|
||||
private Long transferOrderId;
|
||||
private Long transferPalletId;
|
||||
private Long transferItemId;
|
||||
private String customerId;
|
||||
private Integer packageCount;
|
||||
private LocalDateTime createdAt;
|
||||
}
|
||||
+25
@@ -0,0 +1,25 @@
|
||||
package com.baiyue.lastleg.transfer.entity;
|
||||
|
||||
import com.baomidou.mybatisplus.annotation.IdType;
|
||||
import com.baomidou.mybatisplus.annotation.TableId;
|
||||
import com.baomidou.mybatisplus.annotation.TableName;
|
||||
import lombok.Data;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
@Data
|
||||
@TableName("ll_warehouse_transfer_relabel_binding")
|
||||
public class WarehouseTransferRelabelBinding {
|
||||
@TableId(type = IdType.INPUT) private Long id;
|
||||
private Long transferOrderId;
|
||||
private String customerId;
|
||||
private String operationType;
|
||||
private String customerCartonMark;
|
||||
private String originalSku;
|
||||
private String newSku;
|
||||
private Integer quantity;
|
||||
private String fbaCartonMark;
|
||||
private String destinationWarehouseCode;
|
||||
private String remark;
|
||||
private LocalDateTime createdAt;
|
||||
}
|
||||
+13
@@ -4,6 +4,7 @@ import com.baiyue.lastleg.transfer.entity.WarehouseTransferOrder;
|
||||
import org.apache.ibatis.annotations.Mapper;
|
||||
import org.apache.ibatis.annotations.Param;
|
||||
import org.apache.ibatis.annotations.Select;
|
||||
import org.apache.ibatis.annotations.Update;
|
||||
@Mapper public interface WarehouseTransferOrderMapper extends BaseMapper<WarehouseTransferOrder> {
|
||||
@Select("SELECT * FROM ll_warehouse_transfer_order WHERE customer_id=#{customerId} AND idempotency_key=#{key} LIMIT 1")
|
||||
WarehouseTransferOrder findKey(@Param("customerId") String customerId, @Param("key") String key);
|
||||
@@ -11,4 +12,16 @@ import org.apache.ibatis.annotations.Select;
|
||||
WarehouseTransferOrder findNo(@Param("customerId") String customerId, @Param("transferNo") String transferNo);
|
||||
@Select("SELECT * FROM ll_warehouse_transfer_order WHERE customer_id=#{customerId} AND transfer_no=#{transferNo} LIMIT 1 FOR UPDATE")
|
||||
WarehouseTransferOrder lockNo(@Param("customerId") String customerId, @Param("transferNo") String transferNo);
|
||||
@Select("SELECT * FROM ll_warehouse_transfer_order WHERE transfer_no=#{transferNo} AND operating_warehouse_id=#{warehouseId} LIMIT 1 FOR UPDATE")
|
||||
WarehouseTransferOrder lockForPda(@Param("transferNo") String transferNo, @Param("warehouseId") String warehouseId);
|
||||
@Select("SELECT * FROM ll_warehouse_transfer_order WHERE customer_id=#{customerId} AND relabel_no=#{relabelNo} LIMIT 1 FOR UPDATE")
|
||||
WarehouseTransferOrder lockByRelabelNo(@Param("customerId") String customerId, @Param("relabelNo") String relabelNo);
|
||||
@Select("SELECT * FROM ll_warehouse_transfer_order WHERE operating_warehouse_id=#{warehouseId} AND status='WAIT_PDA_RECEIVING' ORDER BY created_at,id")
|
||||
java.util.List<WarehouseTransferOrder> pdaCandidates(@Param("warehouseId") String warehouseId);
|
||||
@Update("UPDATE ll_warehouse_transfer_order SET status='OUTBOUNDED',outbound_at=#{outboundAt},updated_at=#{outboundAt} WHERE customer_id=#{customerId} AND lastleg_order_id=#{orderId} AND outbound_at IS NULL")
|
||||
int markOutboundByOrder(@Param("customerId") String customerId, @Param("orderId") Long orderId,
|
||||
@Param("outboundAt") java.time.LocalDateTime outboundAt);
|
||||
@Update("UPDATE ll_warehouse_transfer_order SET status='OUTBOUNDED',outbound_at=#{outboundAt},updated_at=#{outboundAt} WHERE customer_id=#{customerId} AND relabel_no=#{relabelNo} AND outbound_at IS NULL")
|
||||
int markOutboundByRelabel(@Param("customerId") String customerId, @Param("relabelNo") String relabelNo,
|
||||
@Param("outboundAt") java.time.LocalDateTime outboundAt);
|
||||
}
|
||||
|
||||
+16
@@ -0,0 +1,16 @@
|
||||
package com.baiyue.lastleg.transfer.mapper;
|
||||
|
||||
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
||||
import com.baiyue.lastleg.transfer.entity.WarehouseTransferPalletItem;
|
||||
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 WarehouseTransferPalletItemMapper extends BaseMapper<WarehouseTransferPalletItem> {
|
||||
@Select("SELECT * FROM ll_warehouse_transfer_pallet_item WHERE customer_id=#{customerId} AND transfer_order_id=#{transferOrderId} ORDER BY transfer_pallet_id,id")
|
||||
List<WarehouseTransferPalletItem> listOrder(@Param("customerId") String customerId,
|
||||
@Param("transferOrderId") Long transferOrderId);
|
||||
}
|
||||
+16
@@ -0,0 +1,16 @@
|
||||
package com.baiyue.lastleg.transfer.mapper;
|
||||
|
||||
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
||||
import com.baiyue.lastleg.transfer.entity.WarehouseTransferPallet;
|
||||
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 WarehouseTransferPalletMapper extends BaseMapper<WarehouseTransferPallet> {
|
||||
@Select("SELECT * FROM ll_warehouse_transfer_pallet WHERE customer_id=#{customerId} AND transfer_order_id=#{transferOrderId} ORDER BY sequence_no")
|
||||
List<WarehouseTransferPallet> listOrder(@Param("customerId") String customerId,
|
||||
@Param("transferOrderId") Long transferOrderId);
|
||||
}
|
||||
+16
@@ -0,0 +1,16 @@
|
||||
package com.baiyue.lastleg.transfer.mapper;
|
||||
|
||||
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
||||
import com.baiyue.lastleg.transfer.entity.WarehouseTransferRelabelBinding;
|
||||
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 WarehouseTransferRelabelBindingMapper extends BaseMapper<WarehouseTransferRelabelBinding> {
|
||||
@Select("SELECT * FROM ll_warehouse_transfer_relabel_binding WHERE customer_id=#{customerId} AND transfer_order_id=#{transferOrderId} ORDER BY id")
|
||||
List<WarehouseTransferRelabelBinding> listOrder(@Param("customerId") String customerId,
|
||||
@Param("transferOrderId") Long transferOrderId);
|
||||
}
|
||||
+466
-9
@@ -20,6 +20,20 @@ import com.baiyue.lastleg.inventory.entity.InventoryBalance;
|
||||
import com.baiyue.lastleg.inventory.entity.InventoryPosition;
|
||||
import com.baiyue.lastleg.relabel.entity.RelabelApplication;
|
||||
import com.baiyue.lastleg.relabel.mapper.RelabelApplicationMapper;
|
||||
import com.baiyue.lastleg.relabel.dto.RelabelRequests;
|
||||
import com.baiyue.lastleg.relabel.dto.RelabelResponses;
|
||||
import com.baiyue.lastleg.relabel.service.RelabelApplicationService;
|
||||
import com.baiyue.lastleg.inboundplan.entity.InboundPlan;
|
||||
import com.baiyue.lastleg.inboundplan.entity.InboundPlanLine;
|
||||
import com.baiyue.lastleg.inboundplan.entity.InboundPlanPallet;
|
||||
import com.baiyue.lastleg.inboundplan.entity.InboundPlanPalletAllocation;
|
||||
import com.baiyue.lastleg.inboundplan.mapper.InboundPlanMapper;
|
||||
import com.baiyue.lastleg.inboundplan.mapper.InboundPlanLineMapper;
|
||||
import com.baiyue.lastleg.inboundplan.mapper.InboundPlanPalletMapper;
|
||||
import com.baiyue.lastleg.inboundplan.mapper.InboundPlanPalletAllocationMapper;
|
||||
import com.baiyue.lastleg.inboundplan.pda.entity.InboundStockReceipt;
|
||||
import com.baiyue.lastleg.inboundplan.pda.mapper.InboundStockReceiptMapper;
|
||||
import com.baiyue.lastleg.inboundplan.pda.gateway.WarehouseResourceGateway;
|
||||
import com.baiyue.lastleg.service.LastlegOrderNoGenerator;
|
||||
import com.baiyue.lastleg.transfer.dto.WarehouseTransferRequests;
|
||||
import com.baiyue.lastleg.transfer.dto.WarehouseTransferResponses;
|
||||
@@ -29,6 +43,9 @@ import com.baiyue.lastleg.transfer.entity.WarehouseTransferInventoryAllocation;
|
||||
import com.baiyue.lastleg.transfer.entity.WarehouseTransferOrder;
|
||||
import com.baiyue.lastleg.transfer.entity.WarehouseTransferReceipt;
|
||||
import com.baiyue.lastleg.transfer.entity.WarehouseTransferSourceOrder;
|
||||
import com.baiyue.lastleg.transfer.entity.WarehouseTransferPallet;
|
||||
import com.baiyue.lastleg.transfer.entity.WarehouseTransferPalletItem;
|
||||
import com.baiyue.lastleg.transfer.entity.WarehouseTransferRelabelBinding;
|
||||
import com.baiyue.lastleg.transfer.mapper.InboundSnapshotMapper;
|
||||
import com.baiyue.lastleg.transfer.mapper.WarehouseTransferItemMapper;
|
||||
import com.baiyue.lastleg.transfer.mapper.WarehouseTransferCartonMapper;
|
||||
@@ -36,6 +53,9 @@ import com.baiyue.lastleg.transfer.mapper.WarehouseTransferInventoryAllocationMa
|
||||
import com.baiyue.lastleg.transfer.mapper.WarehouseTransferOrderMapper;
|
||||
import com.baiyue.lastleg.transfer.mapper.WarehouseTransferReceiptMapper;
|
||||
import com.baiyue.lastleg.transfer.mapper.WarehouseTransferSourceOrderMapper;
|
||||
import com.baiyue.lastleg.transfer.mapper.WarehouseTransferPalletMapper;
|
||||
import com.baiyue.lastleg.transfer.mapper.WarehouseTransferPalletItemMapper;
|
||||
import com.baiyue.lastleg.transfer.mapper.WarehouseTransferRelabelBindingMapper;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import jakarta.annotation.Resource;
|
||||
import org.springframework.http.HttpStatus;
|
||||
@@ -53,7 +73,12 @@ import java.util.HexFormat;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.Set;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Comparator;
|
||||
import java.math.BigDecimal;
|
||||
import java.math.RoundingMode;
|
||||
import java.util.function.Function;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
@@ -68,11 +93,18 @@ public class WarehouseTransferService {
|
||||
public static final String OUTBOUNDED = "OUTBOUNDED";
|
||||
public static final String PARTIALLY_RECEIVED = "PARTIALLY_RECEIVED";
|
||||
public static final String RECEIVED = "RECEIVED";
|
||||
public static final String WAIT_PDA_RECEIVING = "WAIT_PDA_RECEIVING";
|
||||
public static final String WAIT_CUSTOMER_CONFIRMATION = "WAIT_CUSTOMER_CONFIRMATION";
|
||||
public static final String READY_FOR_DISPATCH = "READY_FOR_DISPATCH";
|
||||
public static final String WAIT_RELABEL = "WAIT_RELABEL";
|
||||
|
||||
@Resource private WarehouseTransferOrderMapper transfers;
|
||||
@Resource private WarehouseTransferItemMapper transferItems;
|
||||
@Resource private WarehouseTransferCartonMapper transferCartons;
|
||||
@Resource private WarehouseTransferSourceOrderMapper sourceOrders;
|
||||
@Resource private WarehouseTransferPalletMapper transferPallets;
|
||||
@Resource private WarehouseTransferPalletItemMapper transferPalletItems;
|
||||
@Resource private WarehouseTransferRelabelBindingMapper relabelBindings;
|
||||
@Resource private WarehouseTransferInventoryAllocationMapper inventoryAllocations;
|
||||
@Resource private WarehouseTransferReceiptMapper transferReceipts;
|
||||
@Resource private InboundSnapshotMapper inboundSnapshots;
|
||||
@@ -81,6 +113,13 @@ public class WarehouseTransferService {
|
||||
@Resource private LastlegOrderDetailMapper orderDetails;
|
||||
@Resource private LastlegOrderStatusHistoryMapper orderHistories;
|
||||
@Resource private RelabelApplicationMapper relabelApplications;
|
||||
@Resource private RelabelApplicationService relabelService;
|
||||
@Resource private WarehouseResourceGateway warehouseResources;
|
||||
@Resource private InboundPlanMapper inboundPlans;
|
||||
@Resource private InboundPlanLineMapper inboundPlanLines;
|
||||
@Resource private InboundPlanPalletMapper inboundPlanPallets;
|
||||
@Resource private InboundPlanPalletAllocationMapper inboundPlanAllocations;
|
||||
@Resource private InboundStockReceiptMapper stockReceipts;
|
||||
@Resource private LastlegOrderNoGenerator orderNoGenerator;
|
||||
@Resource private InventoryCommandService inventory;
|
||||
@Resource private InventoryCommandMapper inventoryCommands;
|
||||
@@ -93,6 +132,7 @@ public class WarehouseTransferService {
|
||||
if (itemPackages != request.packageCount()) {
|
||||
throw badRequest("Cargo item package total must equal transfer package count");
|
||||
}
|
||||
validateRelabelRequest(request);
|
||||
String key = request.idempotencyKey().trim();
|
||||
String requestHash = hash(request);
|
||||
WarehouseTransferOrder replay = transfers.findKey(customerId, key);
|
||||
@@ -142,10 +182,16 @@ public class WarehouseTransferService {
|
||||
transfer.setFbaWarehouseCode(trim(request.fbaWarehouseCode()));
|
||||
transfer.setDeliveryAddress(request.deliveryAddress().trim()); transfer.setPackageCount(request.packageCount());
|
||||
transfer.setDeliveryMethod(request.deliveryMethod().trim()); transfer.setEstimatedArrivalAt(request.estimatedArrivalAt());
|
||||
transfer.setEstimatedShipAt(request.estimatedShipAt());
|
||||
transfer.setFbaShipmentNo(trim(request.fbaShipmentNo()));
|
||||
transfer.setTrackingNo("CUSTOMER_DELIVERY".equals(request.deliveryMethod().trim()) ? trim(request.trackingNo()) : null);
|
||||
transfer.setFbaBoxNos(trim(request.fbaBoxNos())); transfer.setRemark(trim(request.remark()));
|
||||
transfer.setNeedRelabel(request.needRelabel()); transfer.setStatus(PENDING_REVIEW);
|
||||
transfer.setLabelDeadline(request.labelDeadline());
|
||||
transfer.setRelabelContactName(trim(request.relabelContactName()));
|
||||
transfer.setRelabelContactPhone(trim(request.relabelContactPhone()));
|
||||
transfer.setRelabelChargeAmount(request.relabelChargeAmount());
|
||||
transfer.setRelabelDeliveryMethod(trim(request.relabelDeliveryMethod()));
|
||||
transfer.setIdempotencyKey(key); transfer.setRequestHash(requestHash); transfer.setCreatedBy(trim(operatorId));
|
||||
transfer.setCreatedAt(now); transfer.setUpdatedAt(now);
|
||||
transfers.insert(transfer);
|
||||
@@ -164,14 +210,17 @@ public class WarehouseTransferService {
|
||||
sourceOrders.insert(link);
|
||||
}
|
||||
|
||||
if (request.needRelabel() && request.relabelItems() != null) insertRelabelBindings(customerId, transferId, request.relabelItems(), now);
|
||||
|
||||
int cartonIndex = 0;
|
||||
for (int index = 0; index < request.items().size(); index++) {
|
||||
WarehouseTransferRequests.Item source = request.items().get(index);
|
||||
long itemId = insertTransferItem(customerId, transferId, source, now);
|
||||
List<String> customerMarks = splitMarks(source.shippingMark());
|
||||
for (int itemCarton = 0; itemCarton < source.packageCount(); itemCarton++) {
|
||||
cartonIndex++;
|
||||
insertTransferCarton(customerId, transferId, itemId, transferNo,
|
||||
cartonIndex, request.packageCount(), now);
|
||||
cartonIndex, request.packageCount(), itemCarton < customerMarks.size() ? customerMarks.get(itemCarton) : null, now);
|
||||
}
|
||||
insertOrderDetail(customerId, order.getId(), transferNo, index, source, request, now);
|
||||
}
|
||||
@@ -213,16 +262,36 @@ public class WarehouseTransferService {
|
||||
List<WarehouseTransferResponses.Item> items = transferItems.selectList(
|
||||
new LambdaQueryWrapper<WarehouseTransferItem>().eq(WarehouseTransferItem::getCustomerId, customerId)
|
||||
.eq(WarehouseTransferItem::getTransferOrderId, transfer.getId()).orderByAsc(WarehouseTransferItem::getId))
|
||||
.stream().map(value -> new WarehouseTransferResponses.Item(value.getSkuCode(), value.getProductNameZh(),
|
||||
.stream().map(value -> new WarehouseTransferResponses.Item(value.getId(), value.getSkuCode(), value.getProductNameZh(),
|
||||
value.getPackageCount(), value.getShippingMark())).toList();
|
||||
Map<Long, WarehouseTransferResponses.Item> itemById = items.stream()
|
||||
.collect(Collectors.toMap(WarehouseTransferResponses.Item::id, Function.identity()));
|
||||
List<WarehouseTransferResponses.SourceOrder> sources = sourceOrders.selectList(
|
||||
new LambdaQueryWrapper<WarehouseTransferSourceOrder>().eq(WarehouseTransferSourceOrder::getCustomerId, customerId)
|
||||
.eq(WarehouseTransferSourceOrder::getTransferOrderId, transfer.getId()).orderByAsc(WarehouseTransferSourceOrder::getId))
|
||||
.stream().map(value -> new WarehouseTransferResponses.SourceOrder(value.getSourceLastlegOrderId(),
|
||||
value.getSourceLastlegOrderNo(), value.getInboundOrderId(), value.getInboundCode())).toList();
|
||||
List<WarehouseTransferResponses.Carton> cartons = transferCartons.listOrder(customerId, transfer.getId())
|
||||
.stream().map(value -> new WarehouseTransferResponses.Carton(value.getCartonMark(),
|
||||
.stream().map(value -> new WarehouseTransferResponses.Carton(value.getCartonMark(), value.getCustomerCartonMark(),
|
||||
value.getCartonIndex(), value.getTotalCartons(), value.getStatus())).toList();
|
||||
List<WarehouseTransferPalletItem> palletItemRows = transferPalletItems == null
|
||||
? List.of() : transferPalletItems.listOrder(customerId, transfer.getId());
|
||||
Map<Long, List<WarehouseTransferPalletItem>> palletItemsByPallet = palletItemRows.stream()
|
||||
.collect(Collectors.groupingBy(WarehouseTransferPalletItem::getTransferPalletId));
|
||||
List<WarehouseTransferResponses.Pallet> pallets = transferPallets == null ? List.of() : transferPallets.listOrder(customerId, transfer.getId()).stream()
|
||||
.map(value -> new WarehouseTransferResponses.Pallet(value.getId(), value.getSequenceNo(),
|
||||
value.getWarehousePalletId(), value.getPalletNo(), value.getWarehouseLocationId(),
|
||||
value.getWarehouseLocationCode(), value.getCartonCount(), value.getLengthCm(), value.getWidthCm(),
|
||||
value.getHeightCm(), value.getGrossWeightKg(), value.getVolumeCbm(), value.getStatus(),
|
||||
palletItemsByPallet.getOrDefault(value.getId(), List.of()).stream().map(row -> {
|
||||
WarehouseTransferResponses.Item item = itemById.get(row.getTransferItemId());
|
||||
return new WarehouseTransferResponses.PalletItem(row.getTransferItemId(),
|
||||
item == null ? null : item.skuCode(), row.getPackageCount());
|
||||
}).toList(), value.getCompletedAt())).toList();
|
||||
List<WarehouseTransferResponses.RelabelBinding> bindings = relabelBindings == null ? List.of() : relabelBindings.listOrder(customerId, transfer.getId())
|
||||
.stream().map(value -> new WarehouseTransferResponses.RelabelBinding(value.getOperationType(),
|
||||
value.getCustomerCartonMark(), value.getOriginalSku(), value.getNewSku(), value.getQuantity(),
|
||||
value.getFbaCartonMark(), value.getDestinationWarehouseCode(), value.getRemark())).toList();
|
||||
Map<Long, WarehouseTransferReceipt> receiptByAllocation = transferReceipts.selectList(
|
||||
new LambdaQueryWrapper<WarehouseTransferReceipt>().eq(WarehouseTransferReceipt::getCustomerId, customerId)
|
||||
.eq(WarehouseTransferReceipt::getTransferOrderId, transfer.getId()))
|
||||
@@ -252,9 +321,32 @@ public class WarehouseTransferService {
|
||||
Boolean.TRUE.equals(transfer.getNeedRelabel()), transfer.getRelabelApplicationId(), transfer.getRelabelNo(),
|
||||
relabelStatus,
|
||||
transfer.getOperatingWarehouseId(), transfer.getFbaWarehouseCode(), transfer.getDeliveryAddress(),
|
||||
transfer.getPackageCount(), transfer.getDeliveryMethod(), transfer.getEstimatedArrivalAt(), transfer.getFbaShipmentNo(),
|
||||
transfer.getTrackingNo(), transfer.getFbaBoxNos(), transfer.getRemark(), sources, items, cartons, allocations,
|
||||
transfer.getOutboundAt(), transfer.getCreatedAt());
|
||||
transfer.getPackageCount(), transfer.getDeliveryMethod(), transfer.getEstimatedArrivalAt(),
|
||||
transfer.getEstimatedShipAt(), transfer.getFbaShipmentNo(), transfer.getTrackingNo(), transfer.getFbaBoxNos(),
|
||||
transfer.getRemark(), sources, items, cartons, pallets, bindings, allocations,
|
||||
transfer.getCustomerConfirmedAt(), transfer.getOutboundAt(), transfer.getCreatedAt());
|
||||
}
|
||||
|
||||
@Transactional(readOnly = true)
|
||||
public WarehouseTransferResponses.Label cartonLabel(String customerId, String transferNo) {
|
||||
WarehouseTransferOrder transfer = transfers.findNo(customerId, transferNo);
|
||||
if (transfer == null) throw notFound("Warehouse transfer order not found");
|
||||
List<WarehouseTransferResponses.Carton> cartons = transferCartons.listOrder(customerId, transfer.getId()).stream()
|
||||
.map(value -> new WarehouseTransferResponses.Carton(value.getCartonMark(), value.getCustomerCartonMark(), value.getCartonIndex(), value.getTotalCartons(), value.getStatus())).toList();
|
||||
StringBuilder labels = new StringBuilder();
|
||||
for (WarehouseTransferResponses.Carton carton : cartons) {
|
||||
labels.append("<section class=label><div class=title>仓储转运箱唛</div><div class=mark>")
|
||||
.append(escape(carton.cartonMark())).append("</div><div class=meta>")
|
||||
.append(carton.cartonIndex()).append(" / ").append(carton.totalCartons()).append(" 转运单号:")
|
||||
.append(escape(transferNo)).append("</div>");
|
||||
if (text(carton.customerCartonMark()) != null) labels.append("<div class=customer>客户箱唛:")
|
||||
.append(escape(carton.customerCartonMark())).append("</div>");
|
||||
labels.append("</section>");
|
||||
}
|
||||
String html = "<!doctype html><html><head><meta charset=utf-8><title>" + escape(transferNo) + "-箱唛</title><style>"
|
||||
+ "@page{size:100mm 100mm;margin:8mm}body{margin:0;font-family:Arial,'Microsoft YaHei',sans-serif;color:#111}.label{height:84mm;display:flex;flex-direction:column;align-items:center;justify-content:center;page-break-after:always;border:1px solid #222;box-sizing:border-box;padding:8mm}.title{font-size:18px;font-weight:700}.mark{margin:12mm 0 6mm;font-size:30px;font-weight:700;letter-spacing:1px;word-break:break-all;text-align:center}.meta,.customer{font-size:12px;margin-top:3mm}</style></head><body>"
|
||||
+ labels + "</body></html>";
|
||||
return new WarehouseTransferResponses.Label(transferNo, cartons, html);
|
||||
}
|
||||
|
||||
@Transactional
|
||||
@@ -269,15 +361,18 @@ public class WarehouseTransferService {
|
||||
WarehouseTransferOrder transfer = transfers.lockNo(customerId, transferNo);
|
||||
if (transfer == null) throw notFound("Warehouse transfer order not found");
|
||||
if (!PENDING_REVIEW.equals(transfer.getStatus())) {
|
||||
if (next.equals(transfer.getStatus())) return detail(customerId, transferNo);
|
||||
if (next.equals(transfer.getStatus()) || APPROVED.equals(next)
|
||||
&& Set.of(WAIT_PDA_RECEIVING, WAIT_CUSTOMER_CONFIRMATION, READY_FOR_DISPATCH, WAIT_RELABEL)
|
||||
.contains(transfer.getStatus())) return detail(customerId, transferNo);
|
||||
throw conflict("Warehouse transfer order was already reviewed");
|
||||
}
|
||||
LastlegOrder order = orders.selectById(transfer.getLastlegOrderId());
|
||||
if (order == null || !customerId.equals(order.getCustomerId())) throw conflict("Linked tail-leg order is missing");
|
||||
LocalDateTime now = LocalDateTime.now();
|
||||
String before = order.getCurrentStatus();
|
||||
transfer.setStatus(next); transfer.setUpdatedAt(now); transfers.updateById(transfer);
|
||||
boolean incomingTransit = transfer.getTransferNo().equals(transfer.getInboundCode());
|
||||
String transferStatus = APPROVED.equals(next) && incomingTransit ? WAIT_PDA_RECEIVING : next;
|
||||
transfer.setStatus(transferStatus); transfer.setUpdatedAt(now); transfers.updateById(transfer);
|
||||
String orderStatus = APPROVED.equals(next)
|
||||
? (incomingTransit
|
||||
? ("WAREHOUSE_PICKUP".equals(transfer.getDeliveryMethod()) ? "WAIT_PICKUP" : "WAIT_DELIVERY")
|
||||
@@ -294,6 +389,191 @@ public class WarehouseTransferService {
|
||||
return detail(customerId, transferNo);
|
||||
}
|
||||
|
||||
@Transactional
|
||||
public WarehouseTransferResponses.Detail palletize(String operatorId, long overseasWarehouseId,
|
||||
String transferNo,
|
||||
WarehouseTransferRequests.Palletize request) {
|
||||
WarehouseTransferOrder transfer = transfers.lockForPda(transferNo, String.valueOf(overseasWarehouseId));
|
||||
if (transfer == null) throw notFound("Warehouse transfer order not found");
|
||||
if (!String.valueOf(overseasWarehouseId).equals(transfer.getOperatingWarehouseId())) {
|
||||
throw new ResponseStatusException(HttpStatus.FORBIDDEN, "Warehouse transfer belongs to another warehouse");
|
||||
}
|
||||
String customerId = transfer.getCustomerId();
|
||||
String requestHash = hash(request);
|
||||
if (WAIT_CUSTOMER_CONFIRMATION.equals(transfer.getStatus())
|
||||
&& request.idempotencyKey().equals(transfer.getPalletizeIdempotencyKey())) {
|
||||
if (!requestHash.equals(transfer.getPalletizeRequestHash())) {
|
||||
throw conflict("Palletization idempotency key was reused with different data");
|
||||
}
|
||||
return detail(customerId, transferNo);
|
||||
}
|
||||
if (!WAIT_PDA_RECEIVING.equals(transfer.getStatus())) {
|
||||
throw conflict("Warehouse transfer is not awaiting PDA receiving");
|
||||
}
|
||||
List<WarehouseTransferItem> items = transferItems.selectList(new LambdaQueryWrapper<WarehouseTransferItem>()
|
||||
.eq(WarehouseTransferItem::getCustomerId, customerId)
|
||||
.eq(WarehouseTransferItem::getTransferOrderId, transfer.getId()).orderByAsc(WarehouseTransferItem::getId));
|
||||
Map<Long, WarehouseTransferItem> itemById = items.stream()
|
||||
.collect(Collectors.toMap(WarehouseTransferItem::getId, Function.identity()));
|
||||
Map<Long, Integer> totals = new java.util.HashMap<>();
|
||||
int palletCartons = 0;
|
||||
for (WarehouseTransferRequests.Pallet pallet : request.pallets()) {
|
||||
int itemTotal = pallet.items().stream().mapToInt(WarehouseTransferRequests.PalletItem::packageCount).sum();
|
||||
if (itemTotal != pallet.cartonCount()) throw badRequest("Each pallet carton count must equal its SKU carton total");
|
||||
palletCartons = Math.addExact(palletCartons, pallet.cartonCount());
|
||||
Set<Long> uniqueItems = new HashSet<>();
|
||||
for (WarehouseTransferRequests.PalletItem item : pallet.items()) {
|
||||
if (!uniqueItems.add(item.transferItemId()) || !itemById.containsKey(item.transferItemId())) {
|
||||
throw badRequest("Pallet SKU rows must be unique and belong to this transfer");
|
||||
}
|
||||
totals.merge(item.transferItemId(), item.packageCount(), Math::addExact);
|
||||
}
|
||||
}
|
||||
if (palletCartons != transfer.getPackageCount()) throw badRequest("Pallet carton total must equal transfer package count");
|
||||
for (WarehouseTransferItem item : items) {
|
||||
if (totals.getOrDefault(item.getId(), 0) != item.getPackageCount()) {
|
||||
throw badRequest("Palletized carton total does not match declared SKU " + item.getSkuCode());
|
||||
}
|
||||
}
|
||||
|
||||
String batchKey = "WAREHOUSE_TRANSFER:" + transferNo + ":PALLETIZE";
|
||||
List<WarehouseResourceGateway.PalletBatchItemRequest> batchItems = new ArrayList<>();
|
||||
for (int index = 0; index < request.pallets().size(); index++) {
|
||||
WarehouseTransferRequests.Pallet pallet = request.pallets().get(index);
|
||||
batchItems.add(new WarehouseResourceGateway.PalletBatchItemRequest(Long.parseLong(customerId),
|
||||
transferNo + ":" + (index + 1), transferNo, index + 1, "STANDARD",
|
||||
trim(transfer.getFbaWarehouseCode()), trim(pallet.palletCode())));
|
||||
}
|
||||
WarehouseResourceGateway.PalletBatchResponse ensured = warehouseResources.ensurePalletBatch(
|
||||
new WarehouseResourceGateway.PalletBatchEnsure(overseasWarehouseId, batchKey, batchItems));
|
||||
WarehouseResourceGateway.PalletBatchResponse confirmed = warehouseResources.confirmPalletBatch(
|
||||
new WarehouseResourceGateway.PalletBatchCommand(overseasWarehouseId, batchKey,
|
||||
request.idempotencyKey() + ":CONFIRM"));
|
||||
if (confirmed == null || confirmed.items() == null || confirmed.items().size() != request.pallets().size()) {
|
||||
throw conflict("Warehouse pallet batch did not return every pallet");
|
||||
}
|
||||
LocalDateTime now = LocalDateTime.now();
|
||||
for (int index = 0; index < request.pallets().size(); index++) {
|
||||
int sequenceNo = index + 1;
|
||||
WarehouseTransferRequests.Pallet source = request.pallets().get(index);
|
||||
WarehouseResourceGateway.PalletBatchItem resource = confirmed.items().stream()
|
||||
.filter(value -> value.sequenceNo() == sequenceNo).findFirst()
|
||||
.orElseThrow(() -> conflict("Warehouse pallet sequence is incomplete"));
|
||||
WarehouseResourceGateway.WarehouseLocationReference location = warehouseResources.resolveLocation(
|
||||
overseasWarehouseId, resource.locationId());
|
||||
WarehouseTransferPallet pallet = new WarehouseTransferPallet();
|
||||
pallet.setId(IdWorker.getId()); pallet.setTransferOrderId(transfer.getId()); pallet.setCustomerId(customerId);
|
||||
pallet.setSequenceNo(sequenceNo); pallet.setWarehousePalletId(resource.palletId());
|
||||
pallet.setPalletNo(resource.palletCode()); pallet.setWarehouseLocationId(resource.locationId());
|
||||
pallet.setWarehouseLocationCode(location.locationCode()); pallet.setWarehouseResourceLockId(resource.resourceLockId());
|
||||
// 转运测量以打托后的托盘为单位,体积由 PDA 直接录入托盘总体积,不再按单箱尺寸换算。
|
||||
// 旧表字段仍为 NOT NULL;按托模式不采集长宽高,以 0 兼容存储且不得参与总体积计算。
|
||||
pallet.setLengthCm(BigDecimal.ZERO); pallet.setWidthCm(BigDecimal.ZERO); pallet.setHeightCm(BigDecimal.ZERO);
|
||||
pallet.setCartonCount(source.cartonCount()); pallet.setGrossWeightKg(source.grossWeightKg());
|
||||
pallet.setVolumeCbm(source.volumeCbm().setScale(6, RoundingMode.HALF_UP));
|
||||
pallet.setStatus("COMPLETED"); pallet.setCompletedAt(now); pallet.setCreatedAt(now); pallet.setUpdatedAt(now);
|
||||
transferPallets.insert(pallet);
|
||||
for (WarehouseTransferRequests.PalletItem sourceItem : source.items()) {
|
||||
WarehouseTransferPalletItem row = new WarehouseTransferPalletItem();
|
||||
row.setId(IdWorker.getId()); row.setTransferOrderId(transfer.getId()); row.setTransferPalletId(pallet.getId());
|
||||
row.setTransferItemId(sourceItem.transferItemId()); row.setCustomerId(customerId);
|
||||
row.setPackageCount(sourceItem.packageCount()); row.setCreatedAt(now); transferPalletItems.insert(row);
|
||||
}
|
||||
}
|
||||
transfer.setStatus(WAIT_CUSTOMER_CONFIRMATION); transfer.setPalletizeIdempotencyKey(request.idempotencyKey().trim());
|
||||
transfer.setPalletizeRequestHash(requestHash); transfer.setUpdatedAt(now); transfers.updateById(transfer);
|
||||
LastlegOrder order = requireTailOrder(customerId, transfer); String before = order.getCurrentStatus();
|
||||
order.setCurrentStatus(WAIT_CUSTOMER_CONFIRMATION); order.setPalletCount(request.pallets().size());
|
||||
order.setVolumeCbm(transferPallets.listOrder(customerId, transfer.getId()).stream()
|
||||
.map(WarehouseTransferPallet::getVolumeCbm).reduce(BigDecimal.ZERO, BigDecimal::add));
|
||||
order.setSubOrderStatus("WAREHOUSE_TRANSFER:" + WAIT_CUSTOMER_CONFIRMATION); order.setUpdatedAt(now); orders.updateById(order);
|
||||
insertOrderHistory(customerId, order.getId(), before, order.getCurrentStatus(), transferNo,
|
||||
"PDA receiving measurement and palletization completed", now);
|
||||
return detail(customerId, transferNo);
|
||||
}
|
||||
|
||||
@Transactional
|
||||
public WarehouseTransferResponses.Detail confirmMeasurement(String customerId, String transferNo,
|
||||
String operatorId,
|
||||
WarehouseTransferRequests.CustomerConfirm request) {
|
||||
WarehouseTransferOrder transfer = transfers.lockNo(customerId, transferNo);
|
||||
if (transfer == null) throw notFound("Warehouse transfer order not found");
|
||||
String requestHash = hash(request);
|
||||
if (Set.of(READY_FOR_DISPATCH, WAIT_RELABEL, OUTBOUNDED).contains(transfer.getStatus())
|
||||
&& request.idempotencyKey().equals(transfer.getConfirmationIdempotencyKey())) {
|
||||
if (!requestHash.equals(transfer.getConfirmationRequestHash())) {
|
||||
throw conflict("Confirmation idempotency key was reused with different data");
|
||||
}
|
||||
return detail(customerId, transferNo);
|
||||
}
|
||||
if (!WAIT_CUSTOMER_CONFIRMATION.equals(transfer.getStatus())) {
|
||||
throw conflict("Warehouse transfer measurement is not awaiting customer confirmation");
|
||||
}
|
||||
List<WarehouseTransferItem> items = transferItems.selectList(new LambdaQueryWrapper<WarehouseTransferItem>()
|
||||
.eq(WarehouseTransferItem::getCustomerId, customerId)
|
||||
.eq(WarehouseTransferItem::getTransferOrderId, transfer.getId()).orderByAsc(WarehouseTransferItem::getId));
|
||||
Map<Long, WarehouseTransferItem> itemById = items.stream()
|
||||
.collect(Collectors.toMap(WarehouseTransferItem::getId, Function.identity()));
|
||||
List<WarehouseTransferPallet> pallets = transferPallets.listOrder(customerId, transfer.getId());
|
||||
List<WarehouseTransferPalletItem> palletItems = transferPalletItems.listOrder(customerId, transfer.getId());
|
||||
WarehouseResourceGateway.WarehouseReference warehouse = warehouseResources.requireActiveSharedWarehouse(
|
||||
Long.parseLong(transfer.getOperatingWarehouseId()));
|
||||
Map<String, List<ConfirmedStockSource>> stockSourcesBySku = new java.util.LinkedHashMap<>();
|
||||
LocalDateTime now = LocalDateTime.now();
|
||||
for (WarehouseTransferPallet pallet : pallets) {
|
||||
for (WarehouseTransferPalletItem row : palletItems.stream()
|
||||
.filter(value -> value.getTransferPalletId().equals(pallet.getId())).toList()) {
|
||||
WarehouseTransferItem item = itemById.get(row.getTransferItemId());
|
||||
String operationKey = "WAREHOUSE_TRANSFER_STOCK_IN:" + transferNo + ":" + pallet.getSequenceNo() + ":" + item.getId();
|
||||
InventoryCommandResponse result = inventory.stockIn(customerId, operatorId,
|
||||
new InventoryCommandRequests.StockIn(customerId, "客户-" + customerId,
|
||||
transfer.getOperatingWarehouseId(), warehouse.warehouseCode(), warehouse.warehouseName(),
|
||||
null, trim(transfer.getFbaWarehouseCode()), trim(transfer.getFbaWarehouseCode()),
|
||||
transfer.getInboundOrderId(), transferNo, transferNo, item.getSkuCode(), item.getProductNameZh(), null,
|
||||
pallet.getWarehousePalletId(), pallet.getPalletNo(), transferNo, pallet.getWarehouseLocationId(),
|
||||
pallet.getWarehouseLocationCode(), row.getPackageCount(), transferNo,
|
||||
"WAREHOUSE_TRANSFER_CONFIRMED:" + transferNo, operationKey, trim(request.remark())));
|
||||
stockSourcesBySku.computeIfAbsent(item.getSkuCode(), ignored -> new ArrayList<>())
|
||||
.add(new ConfirmedStockSource(result.balanceId(), result.positionId(), row.getPackageCount()));
|
||||
InboundStockReceipt receipt = new InboundStockReceipt();
|
||||
receipt.setId(IdWorker.getId()); receipt.setCustomerId(customerId);
|
||||
// 转运收货没有独立 PDA 入仓任务,使用本业务链的稳定主键填充通用收货快照维度。
|
||||
receipt.setPlanId(transfer.getInboundOrderId()); receipt.setTaskId(transfer.getId());
|
||||
receipt.setAllocationId(row.getId()); receipt.setLineId(item.getId());
|
||||
receipt.setOrderId(transfer.getLastlegOrderId());
|
||||
receipt.setInboundCode(transferNo); receipt.setSkuCode(item.getSkuCode()); receipt.setProductNameZh(item.getProductNameZh());
|
||||
receipt.setWarehousePalletId(pallet.getWarehousePalletId()); receipt.setPalletNo(pallet.getPalletNo());
|
||||
receipt.setWarehouseLocationId(pallet.getWarehouseLocationId()); receipt.setWarehouseLocationCode(pallet.getWarehouseLocationCode());
|
||||
receipt.setBatchNo(transferNo); receipt.setReceivedPackages(Long.valueOf(row.getPackageCount()));
|
||||
receipt.setInventoryBalanceId(result.balanceId()); receipt.setInventoryPositionId(result.positionId());
|
||||
receipt.setInventoryOperationKey(operationKey); receipt.setReceivedAt(now); receipt.setCreatedAt(now); stockReceipts.insert(receipt);
|
||||
}
|
||||
}
|
||||
if (Boolean.TRUE.equals(transfer.getNeedRelabel())) {
|
||||
RelabelResponses.Detail relabel = createLinkedRelabel(customerId, operatorId, transfer, itemById,
|
||||
stockSourcesBySku);
|
||||
transfer.setRelabelApplicationId(relabel.application().id());
|
||||
transfer.setRelabelNo(relabel.application().relabelNo()); transfer.setStatus(WAIT_RELABEL);
|
||||
} else {
|
||||
if (!StringUtils.hasText(transfer.getFbaWarehouseCode())) {
|
||||
throw conflict("A destination warehouse is required before dispatch");
|
||||
}
|
||||
createDispatchPlan(customerId, transfer, items, pallets, palletItems, now);
|
||||
transfer.setStatus(READY_FOR_DISPATCH);
|
||||
}
|
||||
transfer.setConfirmationIdempotencyKey(request.idempotencyKey().trim());
|
||||
transfer.setConfirmationRequestHash(requestHash); transfer.setCustomerConfirmedAt(now); transfer.setUpdatedAt(now);
|
||||
transfers.updateById(transfer);
|
||||
LastlegOrder order = requireTailOrder(customerId, transfer); String before = order.getCurrentStatus();
|
||||
order.setCurrentStatus(Boolean.TRUE.equals(transfer.getNeedRelabel()) ? WAIT_RELABEL : READY_FOR_DISPATCH);
|
||||
order.setRelabelStatus(Boolean.TRUE.equals(transfer.getNeedRelabel()) ? "PENDING_PROCESSING" : "NOT_REQUIRED");
|
||||
order.setSubOrderStatus("WAREHOUSE_TRANSFER:" + transfer.getStatus() + ";RELABEL:" + order.getRelabelStatus());
|
||||
order.setUpdatedAt(now); orders.updateById(order);
|
||||
insertOrderHistory(customerId, order.getId(), before, order.getCurrentStatus(), transferNo,
|
||||
"Customer confirmed PDA measurements; actual inventory stocked in", now);
|
||||
return detail(customerId, transferNo);
|
||||
}
|
||||
|
||||
@Transactional
|
||||
public WarehouseTransferResponses.Detail allocate(String customerId, String transferNo, String operatorId,
|
||||
WarehouseTransferRequests.Allocate request) {
|
||||
@@ -490,6 +770,182 @@ public class WarehouseTransferService {
|
||||
return detail(customerId, transferNo);
|
||||
}
|
||||
|
||||
@Transactional(readOnly = true)
|
||||
public List<WarehouseTransferResponses.Summary> pdaCandidates(long overseasWarehouseId) {
|
||||
return transfers.pdaCandidates(String.valueOf(overseasWarehouseId)).stream().map(value ->
|
||||
new WarehouseTransferResponses.Summary(value.getId(), value.getTransferNo(), value.getInboundCode(),
|
||||
value.getLastlegOrderId(), value.getLastlegOrderNo(), value.getOperatingWarehouseId(),
|
||||
value.getFbaWarehouseCode(), value.getPackageCount(), value.getDeliveryMethod(),
|
||||
Boolean.TRUE.equals(value.getNeedRelabel()), value.getRelabelNo(), value.getStatus(),
|
||||
value.getEstimatedArrivalAt(), value.getCreatedAt())).toList();
|
||||
}
|
||||
|
||||
private void validateRelabelRequest(WarehouseTransferRequests.Create request) {
|
||||
if (!request.needRelabel()) {
|
||||
if (request.relabelItems() != null && !request.relabelItems().isEmpty()) {
|
||||
throw badRequest("Relabel items require needRelabel=true");
|
||||
}
|
||||
return;
|
||||
}
|
||||
if (request.relabelItems() == null || request.relabelItems().isEmpty()) return;
|
||||
if (request.labelDeadline() == null || !StringUtils.hasText(request.relabelContactName())
|
||||
|| !StringUtils.hasText(request.relabelContactPhone()) || request.relabelChargeAmount() == null) {
|
||||
throw badRequest("Relabel deadline, contact and charge are required");
|
||||
}
|
||||
Set<String> declaredSkus = request.items().stream().map(item -> item.skuCode().trim()).collect(Collectors.toSet());
|
||||
Set<String> marks = new HashSet<>();
|
||||
for (WarehouseTransferRequests.RelabelItem row : request.relabelItems()) {
|
||||
String type = row.operationType().trim().toUpperCase();
|
||||
if (!Set.of("CARTON_LABEL", "SKU_LABEL", "CARTON_AND_SKU").contains(type)) {
|
||||
throw badRequest("Unsupported relabel operation type");
|
||||
}
|
||||
if (!declaredSkus.contains(row.originalSku().trim())) {
|
||||
throw badRequest("Relabel SKU must exist in transfer cargo: " + row.originalSku());
|
||||
}
|
||||
if (("CARTON_LABEL".equals(type) || "CARTON_AND_SKU".equals(type))
|
||||
&& (!StringUtils.hasText(row.fbaCartonMark()) || !StringUtils.hasText(row.destinationWarehouseCode()))) {
|
||||
throw badRequest("Carton relabel requires new FBA carton mark and destination warehouse");
|
||||
}
|
||||
if (("SKU_LABEL".equals(type) || "CARTON_AND_SKU".equals(type)) && !StringUtils.hasText(row.newSku())) {
|
||||
throw badRequest("SKU relabel requires a new SKU");
|
||||
}
|
||||
for (String mark : row.customerCartonMarks()) {
|
||||
if (!marks.add(mark.trim().toUpperCase())) throw badRequest("Customer carton marks must be unique");
|
||||
}
|
||||
}
|
||||
if (marks.size() > request.packageCount()) throw badRequest("Relabel carton marks cannot exceed transfer cartons");
|
||||
}
|
||||
|
||||
private void insertRelabelBindings(String customerId, long transferId,
|
||||
List<WarehouseTransferRequests.RelabelItem> rows, LocalDateTime now) {
|
||||
if (rows == null || rows.isEmpty()) return;
|
||||
for (WarehouseTransferRequests.RelabelItem source : rows) {
|
||||
for (String mark : source.customerCartonMarks()) {
|
||||
WarehouseTransferRelabelBinding row = new WarehouseTransferRelabelBinding();
|
||||
row.setId(IdWorker.getId()); row.setTransferOrderId(transferId); row.setCustomerId(customerId);
|
||||
row.setOperationType(source.operationType().trim().toUpperCase());
|
||||
row.setCustomerCartonMark(mark.trim()); row.setOriginalSku(source.originalSku().trim());
|
||||
row.setNewSku(trim(source.newSku())); row.setQuantity(source.quantity());
|
||||
row.setFbaCartonMark(trim(source.fbaCartonMark()));
|
||||
row.setDestinationWarehouseCode(trim(source.destinationWarehouseCode()));
|
||||
row.setRemark(trim(source.remark())); row.setCreatedAt(now); relabelBindings.insert(row);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private RelabelResponses.Detail createLinkedRelabel(String customerId, String operatorId,
|
||||
WarehouseTransferOrder transfer,
|
||||
Map<Long, WarehouseTransferItem> itemById,
|
||||
Map<String, List<ConfirmedStockSource>> stockSourcesBySku) {
|
||||
Map<String, WarehouseTransferItem> itemsBySku = itemById.values().stream()
|
||||
.collect(Collectors.toMap(WarehouseTransferItem::getSkuCode, Function.identity(), (left, right) -> left));
|
||||
List<RelabelRequests.Item> items = new ArrayList<>();
|
||||
for (WarehouseTransferRelabelBinding binding : relabelBindings.listOrder(customerId, transfer.getId())) {
|
||||
WarehouseTransferItem source = itemsBySku.get(binding.getOriginalSku());
|
||||
ConfirmedStockSource stockSource = nextStockSource(stockSourcesBySku.get(binding.getOriginalSku()));
|
||||
if (source == null || stockSource == null) {
|
||||
throw conflict("Relabel binding cannot find confirmed inventory for SKU " + binding.getOriginalSku());
|
||||
}
|
||||
List<RelabelRequests.SkuItem> skuItems = Set.of("SKU_LABEL", "CARTON_AND_SKU").contains(binding.getOperationType())
|
||||
? List.of(new RelabelRequests.SkuItem(binding.getOriginalSku(), binding.getNewSku(),
|
||||
binding.getQuantity(), binding.getRemark())) : List.of();
|
||||
items.add(new RelabelRequests.Item(stockSource.balanceId, stockSource.positionId, transfer.getInboundOrderId(),
|
||||
binding.getOriginalSku(), null, null, null, source.getProductNameZh(), 1, 1,
|
||||
StringUtils.hasText(transfer.getFbaShipmentNo()) ? transfer.getFbaShipmentNo() : transfer.getTransferNo(),
|
||||
transfer.getTrackingNo(), binding.getNewSku(), "仓储转运自动换标", binding.getRemark(),
|
||||
null, null, null, binding.getCustomerCartonMark(), binding.getFbaCartonMark(),
|
||||
binding.getDestinationWarehouseCode(), binding.getOperationType(), skuItems));
|
||||
}
|
||||
RelabelRequests.Create request = new RelabelRequests.Create(transfer.getTransferNo(),
|
||||
transfer.getOperatingWarehouseId(), transfer.getLabelDeadline(), transfer.getRelabelContactName(),
|
||||
transfer.getRelabelContactPhone(), transfer.getRelabelChargeAmount(), "仓储转运确认后自动创建换标单",
|
||||
"WAREHOUSE_TRANSFER:" + transfer.getTransferNo() + ":RELABEL", items,
|
||||
trim(transfer.getRelabelDeliveryMethod()), false);
|
||||
return relabelService.create(customerId, operatorId, request);
|
||||
}
|
||||
|
||||
private static ConfirmedStockSource nextStockSource(List<ConfirmedStockSource> sources) {
|
||||
if (sources == null) return null;
|
||||
for (ConfirmedStockSource source : sources) {
|
||||
if (source.remainingPackages > 0) {
|
||||
source.remainingPackages--;
|
||||
return source;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private static final class ConfirmedStockSource {
|
||||
private final Long balanceId;
|
||||
private final Long positionId;
|
||||
private int remainingPackages;
|
||||
|
||||
private ConfirmedStockSource(Long balanceId, Long positionId, int remainingPackages) {
|
||||
this.balanceId = balanceId;
|
||||
this.positionId = positionId;
|
||||
this.remainingPackages = remainingPackages;
|
||||
}
|
||||
}
|
||||
|
||||
private void createDispatchPlan(String customerId, WarehouseTransferOrder transfer,
|
||||
List<WarehouseTransferItem> items, List<WarehouseTransferPallet> pallets,
|
||||
List<WarehouseTransferPalletItem> palletItems, LocalDateTime now) {
|
||||
long planId = IdWorker.getId();
|
||||
InboundPlan plan = new InboundPlan(); plan.setId(planId); plan.setPlanNo("WT-" + transfer.getTransferNo());
|
||||
plan.setCustomerId(customerId); plan.setSourceOrderId(transfer.getLastlegOrderId());
|
||||
plan.setContainerNo(transfer.getTransferNo()); plan.setOverseasWarehouseId(Long.parseLong(transfer.getOperatingWarehouseId()));
|
||||
plan.setPlannedArrivalDate(transfer.getEstimatedArrivalAt().toLocalDate()); plan.setPalletType("STANDARD");
|
||||
plan.setAssignedFlag(true); plan.setMergeRequired(false); plan.setUrgentFlag(false);
|
||||
plan.setCreationMode("WAREHOUSE_TRANSFER"); plan.setPlanRemark("Customer-confirmed transfer measurements");
|
||||
plan.setStatus("COMPLETED"); plan.setLineCount(items.size()); plan.setPalletCount(pallets.size());
|
||||
plan.setTotalVolumeCbm(pallets.stream().map(WarehouseTransferPallet::getVolumeCbm)
|
||||
.reduce(BigDecimal.ZERO, BigDecimal::add)); plan.setCreatedAt(now); plan.setUpdatedAt(now); plan.setVersion(0);
|
||||
inboundPlans.insert(plan);
|
||||
Map<Long, Long> lineIds = new java.util.HashMap<>();
|
||||
for (WarehouseTransferItem source : items) {
|
||||
InboundPlanLine line = new InboundPlanLine(); line.setId(IdWorker.getId()); line.setCustomerId(customerId);
|
||||
line.setPlanId(planId); line.setOrderId(transfer.getLastlegOrderId()); line.setInboundCode(transfer.getTransferNo());
|
||||
line.setDestinationType("FBA"); line.setFbaWarehouseCode(transfer.getFbaWarehouseCode());
|
||||
line.setDestinationWarehouseCode(transfer.getFbaWarehouseCode()); line.setDestinationWarehouseName(transfer.getFbaWarehouseCode());
|
||||
line.setVolumeCbm(BigDecimal.ZERO); line.setRequiredPackageCount(source.getPackageCount());
|
||||
line.setPlannedPalletCount((int) palletItems.stream().filter(row -> row.getTransferItemId().equals(source.getId())).count());
|
||||
inboundPlanLines.insert(line); lineIds.put(source.getId(), line.getId());
|
||||
}
|
||||
for (WarehouseTransferPallet source : pallets) {
|
||||
InboundPlanPallet pallet = new InboundPlanPallet(); pallet.setId(IdWorker.getId()); pallet.setCustomerId(customerId);
|
||||
pallet.setPlanId(planId); pallet.setPalletNo(source.getPalletNo()); pallet.setPalletType("STANDARD");
|
||||
pallet.setDestinationWarehouseCode(transfer.getFbaWarehouseCode()); pallet.setDestinationWarehouseName(transfer.getFbaWarehouseCode());
|
||||
pallet.setAllocatedVolumeCbm(source.getVolumeCbm()); pallet.setSequenceNo(source.getSequenceNo());
|
||||
pallet.setWarehousePalletId(source.getWarehousePalletId()); pallet.setWarehouseLocationId(source.getWarehouseLocationId());
|
||||
pallet.setWarehouseResourceLockId(source.getWarehouseResourceLockId()); pallet.setAssignmentStatus("ASSIGNED");
|
||||
pallet.setLockedAt(source.getCompletedAt()); pallet.setActualVolumeCbm(source.getVolumeCbm());
|
||||
pallet.setActualPackageCount(source.getCartonCount()); inboundPlanPallets.insert(pallet);
|
||||
for (WarehouseTransferPalletItem sourceItem : palletItems.stream()
|
||||
.filter(row -> row.getTransferPalletId().equals(source.getId())).toList()) {
|
||||
InboundPlanPalletAllocation allocation = new InboundPlanPalletAllocation(); allocation.setId(IdWorker.getId());
|
||||
allocation.setCustomerId(customerId); allocation.setPlanId(planId); allocation.setLineId(lineIds.get(sourceItem.getTransferItemId()));
|
||||
allocation.setPalletId(pallet.getId()); allocation.setAllocatedVolumeCbm(BigDecimal.ZERO);
|
||||
allocation.setPlannedPackageCount(sourceItem.getPackageCount()); allocation.setCountedPackageCount(sourceItem.getPackageCount());
|
||||
allocation.setPickedPackageCount(0); allocation.setActualVolumeCbm(source.getVolumeCbm());
|
||||
allocation.setStatus("COMPLETED"); allocation.setVersion(0); inboundPlanAllocations.insert(allocation);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static List<String> splitMarks(String value) {
|
||||
if (!StringUtils.hasText(value)) return List.of();
|
||||
return java.util.Arrays.stream(value.split("[,\\n\\r]+"))
|
||||
.map(String::trim).filter(StringUtils::hasText).distinct().toList();
|
||||
}
|
||||
|
||||
private static String escape(String value) {
|
||||
return org.springframework.web.util.HtmlUtils.htmlEscape(Objects.toString(value, ""));
|
||||
}
|
||||
|
||||
private static String text(String value) {
|
||||
return StringUtils.hasText(value) ? value.trim() : null;
|
||||
}
|
||||
|
||||
private Long createInboundSnapshot(String customerId, long inboundOrderId, String transferNo,
|
||||
WarehouseTransferRequests.Create request, String requestHash,
|
||||
LocalDateTime now) {
|
||||
@@ -544,10 +1000,11 @@ public class WarehouseTransferService {
|
||||
|
||||
private void insertTransferCarton(String customerId, long transferId, long transferItemId,
|
||||
String transferNo, int cartonIndex, int totalCartons,
|
||||
LocalDateTime now) {
|
||||
String customerCartonMark, LocalDateTime now) {
|
||||
WarehouseTransferCarton carton = new WarehouseTransferCarton();
|
||||
carton.setId(IdWorker.getId()); carton.setTransferOrderId(transferId); carton.setTransferItemId(transferItemId);
|
||||
carton.setCustomerId(customerId); carton.setCartonMark(transferNo + "#" + totalCartons + "-" + cartonIndex);
|
||||
carton.setCustomerCartonMark(trim(customerCartonMark));
|
||||
carton.setCartonIndex(cartonIndex); carton.setTotalCartons(totalCartons); carton.setStatus("EXPECTED");
|
||||
carton.setCreatedAt(now); carton.setUpdatedAt(now); transferCartons.insert(carton);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user