fix(firstleg): make PDA allocation settlement idempotent

This commit is contained in:
2026-08-10 18:17:53 +08:00
parent a4c47c281c
commit efcd046853
2 changed files with 81 additions and 2 deletions
@@ -86,7 +86,11 @@ public class InboundPalletAllocationRepository {
if (allocated <= picked) {
continue;
}
if (allocation.getId() == null || mapper.markTransferred(allocation.getId(), tenantId, inboundId) != 1) {
if (allocation.getId() == null) {
throw new IllegalStateException("库位资源转移状态已被并发修改");
}
int changed = mapper.markTransferred(allocation.getId(), tenantId, inboundId);
if (changed != 1 && !isAllocationIdState(allocation.getId(), tenantId, inboundId, "TRANSFERRED")) {
throw new IllegalStateException("库位资源转移状态已被并发修改");
}
}
@@ -94,12 +98,32 @@ public class InboundPalletAllocationRepository {
public void markReleased(long tenantId, long inboundId, List<Long> reservationIds) {
for (Long reservationId : reservationIds) {
if (reservationId == null || mapper.markReleased(tenantId, inboundId, reservationId) != 1) {
if (reservationId == null) {
throw new IllegalStateException("库位释放状态已被并发修改");
}
int changed = mapper.markReleased(tenantId, inboundId, reservationId);
if (changed != 1 && !isReservationState(reservationId, tenantId, inboundId, "RELEASED")) {
throw new IllegalStateException("库位释放状态已被并发修改");
}
}
}
private boolean isAllocationIdState(long id, long tenantId, long inboundId, String status) {
InboundPalletAllocationEntity current = mapper.selectOne(new LambdaQueryWrapper<InboundPalletAllocationEntity>()
.eq(InboundPalletAllocationEntity::getTenantId, tenantId)
.eq(InboundPalletAllocationEntity::getInboundId, inboundId)
.eq(InboundPalletAllocationEntity::getId, id));
return current != null && status.equals(current.getAllocationStatus());
}
private boolean isReservationState(long reservationId, long tenantId, long inboundId, String status) {
InboundPalletAllocationEntity current = mapper.selectOne(new LambdaQueryWrapper<InboundPalletAllocationEntity>()
.eq(InboundPalletAllocationEntity::getTenantId, tenantId)
.eq(InboundPalletAllocationEntity::getInboundId, inboundId)
.eq(InboundPalletAllocationEntity::getReservationId, reservationId));
return current != null && status.equals(current.getAllocationStatus());
}
/**
* 依据已经锁定且已扣减本次拣货数量的父单分配,预先固化子单快照。
* 仓库 transfer 是本地事务最后一个外部动作,成功后不再执行本地写入,避免跨服务重试时目标子单变化。