feat: support overseas warehouse locations and A0 overflow
This commit is contained in:
+1
@@ -14,6 +14,7 @@ public record InboundPlanResponse(
|
||||
String customerName,
|
||||
String orderType,
|
||||
String containerNo,
|
||||
Long overseasWarehouseId,
|
||||
String overseasWarehouseCode,
|
||||
String overseasWarehouseName,
|
||||
String status,
|
||||
|
||||
+1
-1
@@ -1124,7 +1124,7 @@ public class InboundPlanService {
|
||||
return new InboundPlanResponse(plan.getId(), plan.getPlanNo(), plan.getCustomerId(), plan.getSourceOrderId(),
|
||||
sourceOrder == null ? null : sourceOrder.orderNo(),
|
||||
sourceOrder == null ? null : sourceOrder.customerName(),
|
||||
sourceOrder == null ? null : sourceOrder.orderType(), plan.getContainerNo(),
|
||||
sourceOrder == null ? null : sourceOrder.orderType(), plan.getContainerNo(), authoritativeWarehouse.warehouseId(),
|
||||
authoritativeWarehouse.warehouseCode(), authoritativeWarehouse.warehouseName(),
|
||||
plan.getStatus(), plan.getLineCount(), plan.getPalletCount(), totalGrossWeightKg,
|
||||
totalNetWeightKg, plan.getTotalVolumeCbm(),
|
||||
|
||||
+42
@@ -0,0 +1,42 @@
|
||||
package com.baiyue.lastleg.pda.move.controller;
|
||||
|
||||
import com.baiyue.common.core.api.ApiResponse;
|
||||
import com.baiyue.common.security.AuthenticatedUser;
|
||||
import com.baiyue.lastleg.pda.move.dto.PlatformInventoryMoveRequest;
|
||||
import com.baiyue.lastleg.pda.move.dto.PdaInventoryMoveResponse;
|
||||
import com.baiyue.lastleg.pda.move.service.PdaInventoryMoveService;
|
||||
import com.baiyue.lastleg.security.OverseasPermissions;
|
||||
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.PostMapping;
|
||||
import org.springframework.web.bind.annotation.RequestBody;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
import org.springframework.web.server.ResponseStatusException;
|
||||
|
||||
/** Browser/platform entry point; the PDA entry point remains restricted to warehouse operators. */
|
||||
@RestController
|
||||
@RequestMapping("/api/platform/v1/last-leg/inventory-moves")
|
||||
@PreAuthorize("hasAuthority('" + OverseasPermissions.INVENTORY_EDIT + "')")
|
||||
public class PlatformInventoryMoveController {
|
||||
@Resource private PdaInventoryMoveService service;
|
||||
|
||||
@PostMapping
|
||||
public ApiResponse<PdaInventoryMoveResponse> move(@AuthenticationPrincipal AuthenticatedUser user,
|
||||
@Valid @RequestBody PlatformInventoryMoveRequest request) {
|
||||
requirePlatform(user);
|
||||
String operator = user.userId() == null ? user.username() : String.valueOf(user.userId());
|
||||
return ApiResponse.success(service.movePlatform(request.overseasWarehouseId(), operator,
|
||||
request.asPdaRequest()));
|
||||
}
|
||||
|
||||
private static void requirePlatform(AuthenticatedUser user) {
|
||||
if (user == null || user.tenantId() == null) throw new ResponseStatusException(HttpStatus.UNAUTHORIZED);
|
||||
if (!"PLATFORM".equals(user.appCode()) || user.tenantId() != 0L) {
|
||||
throw new ResponseStatusException(HttpStatus.FORBIDDEN, "Platform identity is required");
|
||||
}
|
||||
}
|
||||
}
|
||||
+21
@@ -0,0 +1,21 @@
|
||||
package com.baiyue.lastleg.pda.move.dto;
|
||||
|
||||
import jakarta.validation.constraints.NotBlank;
|
||||
import jakarta.validation.constraints.Positive;
|
||||
import jakarta.validation.constraints.PositiveOrZero;
|
||||
import jakarta.validation.constraints.Size;
|
||||
|
||||
/** Platform/admin variant of the pallet put-away command. */
|
||||
public record PlatformInventoryMoveRequest(
|
||||
@Positive long overseasWarehouseId,
|
||||
@NotBlank @Size(max = 128) String sourcePalletCode,
|
||||
@NotBlank @Size(max = 128) String targetLocationCode,
|
||||
@PositiveOrZero int expectedPalletVersion,
|
||||
@NotBlank @Size(max = 128) String idempotencyKey,
|
||||
@NotBlank @Size(max = 500) String reason
|
||||
) {
|
||||
public PdaInventoryMoveRequest asPdaRequest() {
|
||||
return new PdaInventoryMoveRequest(sourcePalletCode, targetLocationCode,
|
||||
expectedPalletVersion, idempotencyKey, reason);
|
||||
}
|
||||
}
|
||||
+21
@@ -45,6 +45,22 @@ public class PdaInventoryMoveService {
|
||||
|
||||
@Transactional
|
||||
public PdaInventoryMoveResponse move(long warehouseId, String operatorKey, PdaInventoryMoveRequest request) {
|
||||
return moveInternal(warehouseId, operatorKey, request);
|
||||
}
|
||||
|
||||
/**
|
||||
* Platform/admin put-away uses the same command, idempotency record and physical
|
||||
* transition as the PDA flow. Keeping one implementation prevents the two entry
|
||||
* points from drifting on A0, virtual-location and inventory-position semantics.
|
||||
*/
|
||||
@Transactional
|
||||
public PdaInventoryMoveResponse movePlatform(long warehouseId, String operatorKey,
|
||||
PdaInventoryMoveRequest request) {
|
||||
return moveInternal(warehouseId, "PLATFORM:" + required(operatorKey, "Operator is required"), request);
|
||||
}
|
||||
|
||||
private PdaInventoryMoveResponse moveInternal(long warehouseId, String operatorKey,
|
||||
PdaInventoryMoveRequest request) {
|
||||
String key = required(request.idempotencyKey(), "Idempotency key is required");
|
||||
String requestHash = hash(request);
|
||||
PdaInventoryMove existing = moves.find(warehouseId, operatorKey, key);
|
||||
@@ -58,6 +74,11 @@ public class PdaInventoryMoveService {
|
||||
if (!Set.of("ACTIVE", "IDLE", "OCCUPIED").contains(target.status())) {
|
||||
throw conflict("Target location is not available");
|
||||
}
|
||||
// A virtual receiving location is an intake staging position, not a put-away
|
||||
// destination. A0 is deliberately allowed as a shared overflow location.
|
||||
if ("VIRTUAL".equalsIgnoreCase(target.locationType())) {
|
||||
throw conflict("Virtual receiving location cannot be used as a put-away target");
|
||||
}
|
||||
boolean recoveringRemoteSuccess = pallet.locationId() == target.locationId()
|
||||
&& pallet.version() == request.expectedPalletVersion() + 1;
|
||||
if (!recoveringRemoteSuccess && pallet.version() != request.expectedPalletVersion()) {
|
||||
|
||||
Reference in New Issue
Block a user