This commit is contained in:
2026-10-14 18:01:25 +08:00
parent 8bc8518496
commit 471e50ffe1
34 changed files with 1088 additions and 71 deletions
@@ -294,6 +294,40 @@ public class InventoryCommandService {
}
}
/** Internal discard workflow: remove only stock held by the same discard item. */
@Transactional
public InventoryCommandResponse discardHeld(String customerId, String operatorId, InventoryCommandRequests.Move request) {
if (request.packages() <= 0) throw badRequest("废弃数量必须为正数");
return execute(customerId, operatorId, "DISCARD", request.idempotencyKey(), request, operation -> {
Locked locked = locked(customerId, request.positionId());
InventoryPosition position = locked.position();
InventoryBalance balance = locked.balance();
requireReservation(customerId, request.positionId(), null, request.packages(), "DISCARD");
long owned = ledgers.orderHoldCycle(customerId, balance.getInboundOrderId(),
required(request.sourceEventId(), "废弃库存预留标识不能为空")).stream()
.filter(l -> Objects.equals(l.getPositionId(), position.getId())
&& Objects.equals(l.getBusinessOrderNo(), request.businessOrderNo()))
.mapToLong(l -> value(l.getDeltaPackages())).sum();
requireAtLeast(owned, request.packages(), "discard reservation");
long before = value(position.getHoldPackages());
requireAtLeast(before, request.packages(), "held");
requireAtLeast(value(balance.getHoldPackages()), request.packages(), "balance held");
position.setHoldPackages(before - request.packages());
position.setStatus(positionPackages(position) == 0 ? "EMPTY" : "OCCUPIED");
position.setVersion(value(position.getVersion()) + 1); position.setUpdatedAt(LocalDateTime.now());
positions.updateById(position);
balance.setHoldPackages(value(balance.getHoldPackages()) - request.packages()); touch(balance);
balances.updateById(balance);
boolean empty = position.getPalletId() != null && commands.palletPackages(position.getPalletId()) == 0;
if (empty) warehouseGateway.scrapPallet(customerId, position.getPalletId());
ledger(customerId, operatorId, operation.getId(), balance, position, balance.getSkuCode(), "DISCARD",
"HOLD", "DISCARDED", before, -request.packages(), before - request.packages(),
request.businessOrderNo(), balance.getInboundOrderNo(), request.outboundOrderNo(), request.sourceEventId(),
request.idempotencyKey(), request.remark());
return response(operation, balance, position, empty);
});
}
private InventoryCommandResponse ship(String customerId, String operatorId,
InventoryCommandRequests.Move request, String skuSnapshot) {
return ship(customerId, operatorId, request, skuSnapshot, null);