fix(lastleg): complete stock transfer through linked relabel
This commit is contained in:
+70
-6
@@ -36,6 +36,8 @@ import java.util.Objects;
|
||||
|
||||
@Service
|
||||
public class InventoryCommandService {
|
||||
private record TransferMoveSnapshot(InventoryCommandRequests.Move move, String sku) {}
|
||||
private record TransferAdjustmentSnapshot(InventoryCommandRequests.Adjustment adjustment, String sku) {}
|
||||
@Resource private InventoryBalanceMapper balances;
|
||||
@Resource private InventoryPositionMapper positions;
|
||||
@Resource private InventoryLedgerMapper ledgers;
|
||||
@@ -237,7 +239,35 @@ public class InventoryCommandService {
|
||||
|
||||
@Transactional
|
||||
public InventoryCommandResponse ship(String customerId, String operatorId, InventoryCommandRequests.Move request) {
|
||||
return execute(customerId, operatorId, "SHIP", request.idempotencyKey(), request, operation -> {
|
||||
return ship(customerId, operatorId, request, null);
|
||||
}
|
||||
|
||||
@Transactional
|
||||
public InventoryCommandResponse allocateTransferSnapshot(String customerId, String operatorId,
|
||||
InventoryCommandRequests.Move request, String skuSnapshot) {
|
||||
requireTransferSku(request.idempotencyKey(), skuSnapshot);
|
||||
return move(customerId, operatorId, "ALLOCATE", Bucket.AVAILABLE, Bucket.ALLOCATED, request, skuSnapshot);
|
||||
}
|
||||
|
||||
@Transactional
|
||||
public InventoryCommandResponse pickTransferSnapshot(String customerId, String operatorId,
|
||||
InventoryCommandRequests.Move request, String skuSnapshot) {
|
||||
requireTransferSku(request.idempotencyKey(), skuSnapshot);
|
||||
return move(customerId, operatorId, "PICK", Bucket.ALLOCATED, Bucket.PICKED, request, skuSnapshot);
|
||||
}
|
||||
|
||||
/** Exact source snapshot comes from the transfer's locked allocation, not a mixed order aggregate. */
|
||||
@Transactional
|
||||
public InventoryCommandResponse shipTransferSnapshot(String customerId, String operatorId,
|
||||
InventoryCommandRequests.Move request, String skuSnapshot) {
|
||||
requireTransferSku(request.idempotencyKey(), skuSnapshot);
|
||||
return ship(customerId, operatorId, request, skuSnapshot);
|
||||
}
|
||||
|
||||
private InventoryCommandResponse ship(String customerId, String operatorId,
|
||||
InventoryCommandRequests.Move request, String skuSnapshot) {
|
||||
return execute(customerId, operatorId, "SHIP", request.idempotencyKey(),
|
||||
skuSnapshot == null ? request : new TransferMoveSnapshot(request, skuSnapshot), operation -> {
|
||||
Locked locked = locked(customerId, request.positionId());
|
||||
InventoryPosition position = locked.position();
|
||||
InventoryBalance balance = locked.balance();
|
||||
@@ -255,7 +285,8 @@ public class InventoryCommandService {
|
||||
balances.updateById(balance);
|
||||
boolean palletEmpty = commands.palletPackages(position.getPalletId()) == 0;
|
||||
if (palletEmpty) warehouseGateway.scrapPallet(customerId, position.getPalletId());
|
||||
ledger(customerId, operatorId, operation.getId(), balance, position, balance.getSkuCode(), "SHIP",
|
||||
ledger(customerId, operatorId, operation.getId(), balance, position,
|
||||
skuSnapshot == null ? balance.getSkuCode() : skuSnapshot, "SHIP",
|
||||
"PICKED", "SHIPPED", before, -request.packages(), before - request.packages(),
|
||||
request.businessOrderNo(), null, request.outboundOrderNo(), request.sourceEventId(),
|
||||
request.idempotencyKey(), request.remark());
|
||||
@@ -471,10 +502,23 @@ public class InventoryCommandService {
|
||||
@Transactional
|
||||
public InventoryCommandResponse adjust(String customerId, String operatorId,
|
||||
InventoryCommandRequests.Adjustment request) {
|
||||
return adjust(customerId, operatorId, request, null);
|
||||
}
|
||||
|
||||
@Transactional
|
||||
public InventoryCommandResponse adjustTransferRelabel(String customerId, String operatorId,
|
||||
InventoryCommandRequests.Adjustment request, String skuSnapshot) {
|
||||
requireTransferSku(request.idempotencyKey(), skuSnapshot);
|
||||
return adjust(customerId, operatorId, request, skuSnapshot);
|
||||
}
|
||||
|
||||
private InventoryCommandResponse adjust(String customerId, String operatorId,
|
||||
InventoryCommandRequests.Adjustment request, String skuSnapshot) {
|
||||
if (request.packageDelta() == 0) {
|
||||
throw badRequest("Adjustment package delta cannot be zero");
|
||||
}
|
||||
return execute(customerId, operatorId, "ADJUST", request.idempotencyKey(), request, operation -> {
|
||||
return execute(customerId, operatorId, "ADJUST", request.idempotencyKey(),
|
||||
skuSnapshot == null ? request : new TransferAdjustmentSnapshot(request, skuSnapshot), operation -> {
|
||||
Locked locked = locked(customerId, request.positionId());
|
||||
InventoryPosition position = locked.position();
|
||||
InventoryBalance balance = locked.balance();
|
||||
@@ -492,7 +536,8 @@ public class InventoryCommandService {
|
||||
balance.setAvailablePackages(balanceAfter);
|
||||
touch(balance);
|
||||
balances.updateById(balance);
|
||||
ledger(customerId, operatorId, operation.getId(), balance, position, balance.getSkuCode(), "ADJUST",
|
||||
ledger(customerId, operatorId, operation.getId(), balance, position,
|
||||
skuSnapshot == null ? balance.getSkuCode() : skuSnapshot, "ADJUST",
|
||||
"AVAILABLE", "AVAILABLE", before, request.packageDelta(), after,
|
||||
request.businessOrderNo(), null, null, null, request.idempotencyKey(),
|
||||
request.reason() + remarkSuffix(request.remark()));
|
||||
@@ -507,7 +552,25 @@ public class InventoryCommandService {
|
||||
|
||||
private InventoryCommandResponse move(String customerId, String operatorId, String operationType,
|
||||
Bucket from, Bucket to, InventoryCommandRequests.Move request) {
|
||||
return execute(customerId, operatorId, operationType, request.idempotencyKey(), request, operation -> {
|
||||
return move(customerId, operatorId, operationType, from, to, request, null);
|
||||
}
|
||||
|
||||
@Transactional
|
||||
public InventoryCommandResponse releaseTransferRelabel(String customerId, String operatorId,
|
||||
InventoryCommandRequests.Move request, String skuSnapshot) {
|
||||
requireTransferSku(request.idempotencyKey(), skuSnapshot);
|
||||
return move(customerId, operatorId, "RELEASE", Bucket.HOLD, Bucket.AVAILABLE, request, skuSnapshot);
|
||||
}
|
||||
|
||||
private static void requireTransferSku(String key, String skuSnapshot) {
|
||||
if (key == null || !key.startsWith("WAREHOUSE_TRANSFER:") || skuSnapshot == null || skuSnapshot.isBlank()
|
||||
|| "MIXED".equals(skuSnapshot)) throw badRequest("Exact warehouse transfer SKU snapshot is required");
|
||||
}
|
||||
|
||||
private InventoryCommandResponse move(String customerId, String operatorId, String operationType,
|
||||
Bucket from, Bucket to, InventoryCommandRequests.Move request, String skuSnapshot) {
|
||||
return execute(customerId, operatorId, operationType, request.idempotencyKey(),
|
||||
skuSnapshot == null ? request : new TransferMoveSnapshot(request, skuSnapshot), operation -> {
|
||||
Locked locked = locked(customerId, request.positionId());
|
||||
InventoryPosition position = locked.position();
|
||||
InventoryBalance balance = locked.balance();
|
||||
@@ -524,7 +587,8 @@ public class InventoryCommandService {
|
||||
packages(balance, to, packages(balance, to) + request.packages());
|
||||
touch(balance);
|
||||
balances.updateById(balance);
|
||||
ledger(customerId, operatorId, operation.getId(), balance, position, balance.getSkuCode(), operationType,
|
||||
ledger(customerId, operatorId, operation.getId(), balance, position,
|
||||
skuSnapshot == null ? balance.getSkuCode() : skuSnapshot, operationType,
|
||||
from.name(), to.name(), beforeTarget, request.packages(), beforeTarget + request.packages(),
|
||||
request.businessOrderNo(), null, request.outboundOrderNo(), request.sourceEventId(),
|
||||
request.idempotencyKey(), request.remark());
|
||||
|
||||
Reference in New Issue
Block a user