feat:去除班次里面的库存,所有库存操作统一到库存表处理

This commit is contained in:
amos
2026-02-25 15:54:06 +08:00
parent 12521f5512
commit ebc8aaf9b3
5 changed files with 207 additions and 132 deletions

View File

@@ -58,21 +58,6 @@ public class FixedScheduleDO implements Serializable {
*/
private String price;
/**
* 总座位数
*/
private Integer totalSeats;
/**
* 已售座位数
*/
private Integer soldSeats;
/**
* 可用座位数
*/
private Integer availableSeats;
/**
* 创建时间
*/

View File

@@ -47,21 +47,6 @@ public class RollingScheduleDO implements Serializable {
* 状态1-运营中0-已停运
*/
private Integer status;
/**
* 总座位数
*/
private Integer totalSeats;
/**
* 已售座位数
*/
private Integer soldSeats;
/**
* 可用座位数
*/
private Integer availableSeats;
/**
* 创建时间

View File

@@ -27,9 +27,9 @@ public class FixedSchedule implements Serializable {
private String scheduleCode;
/**
* 库存编码引用Inventory
* 库存信息
*/
private String inventoryCode;
private Inventory inventory;
/**
* 班次日期
@@ -51,21 +51,6 @@ public class FixedSchedule implements Serializable {
*/
private BigDecimal price;
/**
* 总座位数
*/
private Integer totalSeats;
/**
* 已售座位数
*/
private Integer soldSeats;
/**
* 可用座位数
*/
private Integer availableSeats;
/**
* 创建时间
*/

View File

@@ -26,9 +26,9 @@ public class RollingSchedule implements Serializable {
private String rollingScheduleCode;
/**
* 库存编码引用Inventory
* 库存信息
*/
private String inventoryCode;
private Inventory inventory;
/**
* 班次日期

View File

@@ -11,10 +11,12 @@ import pers.amos.mall.common.enums.OrderTypeEnum;
import pers.amos.mall.common.log.LogUtil;
import pers.amos.mall.common.response.Result;
import pers.amos.mall.route.dal.dataobject.FixedScheduleDO;
import pers.amos.mall.route.dal.dataobject.InventoryDO;
import pers.amos.mall.route.dal.dataobject.InventoryLogDO;
import pers.amos.mall.route.dal.dataobject.RollingScheduleDO;
import pers.amos.mall.route.dal.repository.FixedScheduleRepository;
import pers.amos.mall.route.dal.repository.InventoryLogRepository;
import pers.amos.mall.route.dal.repository.InventoryRepository;
import pers.amos.mall.route.dal.repository.RollingScheduleRepository;
import java.time.LocalDateTime;
@@ -31,6 +33,9 @@ public class RouteServiceImpl implements RouteService {
@Autowired
private RollingScheduleRepository rollingScheduleRepository;
@Autowired
private InventoryRepository inventoryRepository;
@Autowired
private InventoryLogRepository inventoryLogRepository;
@@ -73,6 +78,7 @@ public class RouteServiceImpl implements RouteService {
// ==================== 固定班次库存操作 ====================
private Result<Boolean> checkFixedScheduleInventory(InventoryCheckDTO dto) {
// 1. 查询固定班次
FixedScheduleDO schedule = fixedScheduleRepository.getOne(
Wrappers.lambdaQuery(FixedScheduleDO.class)
.eq(FixedScheduleDO::getScheduleCode, dto.getScheduleCode())
@@ -82,7 +88,15 @@ public class RouteServiceImpl implements RouteService {
return Result.fail("SCHEDULE_NOT_FOUND", "班次不存在");
}
if (schedule.getAvailableSeats() < dto.getQuantity()) {
// 2. 通过库存编码查询库存
InventoryDO inventory = inventoryRepository.findByInventoryCode(schedule.getInventoryCode());
if (inventory == null) {
return Result.fail("INVENTORY_NOT_FOUND", "库存不存在");
}
// 3. 检查剩余库存
if (inventory.getRemainingStock() < dto.getQuantity()) {
return Result.fail("INSUFFICIENT_INVENTORY", "库存不足");
}
@@ -90,6 +104,7 @@ public class RouteServiceImpl implements RouteService {
}
private Result<Boolean> lockFixedScheduleInventory(InventoryOperationDTO dto) {
// 1. 查询固定班次
FixedScheduleDO schedule = fixedScheduleRepository.getOne(
Wrappers.lambdaQuery(FixedScheduleDO.class)
.eq(FixedScheduleDO::getScheduleCode, dto.getScheduleCode())
@@ -99,33 +114,47 @@ public class RouteServiceImpl implements RouteService {
return Result.fail("SCHEDULE_NOT_FOUND", "班次不存在");
}
Integer beforeQty = schedule.getAvailableSeats();
// 2. 查询库存
InventoryDO inventory = inventoryRepository.findByInventoryCode(schedule.getInventoryCode());
// 扣减可用库存
boolean success = fixedScheduleRepository.update(
Wrappers.lambdaUpdate(FixedScheduleDO.class)
.eq(FixedScheduleDO::getScheduleCode, dto.getScheduleCode())
.setSql("available_seats = available_seats - " + dto.getQuantity())
.ge(FixedScheduleDO::getAvailableSeats, dto.getQuantity())
);
if (inventory == null) {
return Result.fail("INVENTORY_NOT_FOUND", "库存不存在");
}
Integer beforeQty = inventory.getRemainingStock();
// 3. 扣减剩余库存(使用乐观锁)
inventory.setRemainingStock(inventory.getRemainingStock() - dto.getQuantity());
inventory.setUpdateTime(LocalDateTime.now());
boolean success = inventoryRepository.updateWithVersion(inventory);
if (!success) {
return Result.fail("INVENTORY_LOCK_FAILED", "库存锁定失败,可能库存不足或并发冲突");
}
// 记录库存日志
saveInventoryLog(OrderTypeEnum.FIXED.getCode(), dto.getScheduleCode(), null, InventoryOperationTypeEnum.LOCK.getCode(),
dto.getQuantity(), beforeQty, beforeQty - dto.getQuantity(),
dto.getOrderNo(), "锁定库存");
// 4. 记录库存日志
saveInventoryLog(
OrderTypeEnum.FIXED.getCode(),
dto.getScheduleCode(),
null,
schedule.getInventoryCode(),
InventoryOperationTypeEnum.LOCK.getCode(),
dto.getQuantity(),
beforeQty,
beforeQty - dto.getQuantity(),
dto.getOrderNo(),
"锁定库存"
);
LogUtil.info("固定班次库存锁定成功, scheduleCode={}, quantity={}, orderNo={}",
dto.getScheduleCode(), dto.getQuantity(), dto.getOrderNo());
LogUtil.info("固定班次库存锁定成功, scheduleCode={}, inventoryCode={}, quantity={}, orderNo={}",
dto.getScheduleCode(), schedule.getInventoryCode(), dto.getQuantity(), dto.getOrderNo());
return Result.success(true);
}
private Result<Boolean> deductFixedScheduleInventory(InventoryOperationDTO dto) {
// 固定班次在锁定时已经扣减了available_seats这里只需要增加sold_seats
// 1. 查询固定班次
FixedScheduleDO schedule = fixedScheduleRepository.getOne(
Wrappers.lambdaQuery(FixedScheduleDO.class)
.eq(FixedScheduleDO::getScheduleCode, dto.getScheduleCode())
@@ -135,26 +164,43 @@ public class RouteServiceImpl implements RouteService {
return Result.fail("SCHEDULE_NOT_FOUND", "班次不存在");
}
Integer beforeSold = schedule.getSoldSeats();
// 2. 查询库存
InventoryDO inventory = inventoryRepository.findByInventoryCode(schedule.getInventoryCode());
fixedScheduleRepository.update(
Wrappers.lambdaUpdate(FixedScheduleDO.class)
.eq(FixedScheduleDO::getScheduleCode, dto.getScheduleCode())
.setSql("sold_seats = sold_seats + " + dto.getQuantity())
if (inventory == null) {
return Result.fail("INVENTORY_NOT_FOUND", "库存不存在");
}
Integer beforeSold = inventory.getSoldStock();
// 3. 增加已售库存
inventory.setSoldStock(inventory.getSoldStock() + dto.getQuantity());
inventory.setUpdateTime(LocalDateTime.now());
inventoryRepository.save(inventory);
// 4. 记录库存日志
saveInventoryLog(
OrderTypeEnum.FIXED.getCode(),
dto.getScheduleCode(),
null,
schedule.getInventoryCode(),
InventoryOperationTypeEnum.DEDUCT.getCode(),
dto.getQuantity(),
beforeSold,
beforeSold + dto.getQuantity(),
dto.getOrderNo(),
"扣减库存(支付成功)"
);
// 记录库存日志
saveInventoryLog(OrderTypeEnum.FIXED.getCode(), dto.getScheduleCode(), null, InventoryOperationTypeEnum.DEDUCT.getCode(),
dto.getQuantity(), beforeSold, beforeSold + dto.getQuantity(),
dto.getOrderNo(), "扣减库存(支付成功)");
LogUtil.info("固定班次库存扣减成功, scheduleCode={}, quantity={}, orderNo={}",
dto.getScheduleCode(), dto.getQuantity(), dto.getOrderNo());
LogUtil.info("固定班次库存扣减成功, scheduleCode={}, inventoryCode={}, quantity={}, orderNo={}",
dto.getScheduleCode(), schedule.getInventoryCode(), dto.getQuantity(), dto.getOrderNo());
return Result.success(true);
}
private Result<Boolean> releaseFixedScheduleInventory(InventoryOperationDTO dto) {
// 1. 查询固定班次
FixedScheduleDO schedule = fixedScheduleRepository.getOne(
Wrappers.lambdaQuery(FixedScheduleDO.class)
.eq(FixedScheduleDO::getScheduleCode, dto.getScheduleCode())
@@ -164,22 +210,37 @@ public class RouteServiceImpl implements RouteService {
return Result.fail("SCHEDULE_NOT_FOUND", "班次不存在");
}
Integer beforeQty = schedule.getAvailableSeats();
// 2. 查询库存
InventoryDO inventory = inventoryRepository.findByInventoryCode(schedule.getInventoryCode());
// 释放库存
fixedScheduleRepository.update(
Wrappers.lambdaUpdate(FixedScheduleDO.class)
.eq(FixedScheduleDO::getScheduleCode, dto.getScheduleCode())
.setSql("available_seats = available_seats + " + dto.getQuantity())
if (inventory == null) {
return Result.fail("INVENTORY_NOT_FOUND", "库存不存在");
}
Integer beforeQty = inventory.getRemainingStock();
// 3. 释放库存(增加剩余库存)
inventory.setRemainingStock(inventory.getRemainingStock() + dto.getQuantity());
inventory.setUpdateTime(LocalDateTime.now());
inventoryRepository.save(inventory);
// 4. 记录库存日志
saveInventoryLog(
OrderTypeEnum.FIXED.getCode(),
dto.getScheduleCode(),
null,
schedule.getInventoryCode(),
InventoryOperationTypeEnum.RELEASE.getCode(),
dto.getQuantity(),
beforeQty,
beforeQty + dto.getQuantity(),
dto.getOrderNo(),
"释放库存(订单取消/超时)"
);
// 记录库存日志
saveInventoryLog(OrderTypeEnum.FIXED.getCode(), dto.getScheduleCode(), null, InventoryOperationTypeEnum.RELEASE.getCode(),
dto.getQuantity(), beforeQty, beforeQty + dto.getQuantity(),
dto.getOrderNo(), "释放库存(订单取消/超时)");
LogUtil.info("固定班次库存释放成功, scheduleCode={}, quantity={}, orderNo={}",
dto.getScheduleCode(), dto.getQuantity(), dto.getOrderNo());
LogUtil.info("固定班次库存释放成功, scheduleCode={}, inventoryCode={}, quantity={}, orderNo={}",
dto.getScheduleCode(), schedule.getInventoryCode(), dto.getQuantity(), dto.getOrderNo());
return Result.success(true);
}
@@ -187,6 +248,7 @@ public class RouteServiceImpl implements RouteService {
// ==================== 滚动班次库存操作 ====================
private Result<Boolean> checkRollingScheduleInventory(InventoryCheckDTO dto) {
// 1. 查询滚动班次
RollingScheduleDO schedule = rollingScheduleRepository.getOne(
Wrappers.lambdaQuery(RollingScheduleDO.class)
.eq(RollingScheduleDO::getRollingScheduleCode, dto.getRollingScheduleCode())
@@ -196,7 +258,15 @@ public class RouteServiceImpl implements RouteService {
return Result.fail("SCHEDULE_NOT_FOUND", "滚动班次不存在");
}
if (schedule.getAvailableSeats() < dto.getQuantity()) {
// 2. 通过库存编码查询库存
InventoryDO inventory = inventoryRepository.findByInventoryCode(schedule.getInventoryCode());
if (inventory == null) {
return Result.fail("INVENTORY_NOT_FOUND", "库存不存在");
}
// 3. 检查剩余库存
if (inventory.getRemainingStock() < dto.getQuantity()) {
return Result.fail("INSUFFICIENT_INVENTORY", "库存不足");
}
@@ -204,6 +274,7 @@ public class RouteServiceImpl implements RouteService {
}
private Result<Boolean> lockRollingScheduleInventory(InventoryOperationDTO dto) {
// 1. 查询滚动班次
RollingScheduleDO schedule = rollingScheduleRepository.getOne(
Wrappers.lambdaQuery(RollingScheduleDO.class)
.eq(RollingScheduleDO::getRollingScheduleCode, dto.getRollingScheduleCode())
@@ -213,32 +284,47 @@ public class RouteServiceImpl implements RouteService {
return Result.fail("SCHEDULE_NOT_FOUND", "滚动班次不存在");
}
Integer beforeQty = schedule.getAvailableSeats();
// 2. 查询库存
InventoryDO inventory = inventoryRepository.findByInventoryCode(schedule.getInventoryCode());
// 乐观锁扣减共享库存池
boolean success = rollingScheduleRepository.update(
Wrappers.lambdaUpdate(RollingScheduleDO.class)
.eq(RollingScheduleDO::getRollingScheduleCode, dto.getRollingScheduleCode())
.setSql("available_seats = available_seats - " + dto.getQuantity())
.ge(RollingScheduleDO::getAvailableSeats, dto.getQuantity())
);
if (inventory == null) {
return Result.fail("INVENTORY_NOT_FOUND", "库存不存在");
}
Integer beforeQty = inventory.getRemainingStock();
// 3. 扣减剩余库存(使用乐观锁)
inventory.setRemainingStock(inventory.getRemainingStock() - dto.getQuantity());
inventory.setUpdateTime(LocalDateTime.now());
boolean success = inventoryRepository.updateWithVersion(inventory);
if (!success) {
return Result.fail("INVENTORY_LOCK_FAILED", "库存锁定失败,可能库存不足或并发冲突");
}
// 记录库存日志
saveInventoryLog(OrderTypeEnum.ROLLING.getCode(), null, dto.getRollingScheduleCode(), InventoryOperationTypeEnum.LOCK.getCode(),
dto.getQuantity(), beforeQty, beforeQty - dto.getQuantity(),
dto.getOrderNo(), "锁定共享库存池");
// 4. 记录库存日志
saveInventoryLog(
OrderTypeEnum.ROLLING.getCode(),
null,
dto.getRollingScheduleCode(),
schedule.getInventoryCode(),
InventoryOperationTypeEnum.LOCK.getCode(),
dto.getQuantity(),
beforeQty,
beforeQty - dto.getQuantity(),
dto.getOrderNo(),
"锁定共享库存池"
);
LogUtil.info("滚动班次库存锁定成功, rollingScheduleCode={}, quantity={}, orderNo={}",
dto.getRollingScheduleCode(), dto.getQuantity(), dto.getOrderNo());
LogUtil.info("滚动班次库存锁定成功, rollingScheduleCode={}, inventoryCode={}, quantity={}, orderNo={}",
dto.getRollingScheduleCode(), schedule.getInventoryCode(), dto.getQuantity(), dto.getOrderNo());
return Result.success(true);
}
private Result<Boolean> deductRollingScheduleInventory(InventoryOperationDTO dto) {
// 1. 查询滚动班次
RollingScheduleDO schedule = rollingScheduleRepository.getOne(
Wrappers.lambdaQuery(RollingScheduleDO.class)
.eq(RollingScheduleDO::getRollingScheduleCode, dto.getRollingScheduleCode())
@@ -248,26 +334,43 @@ public class RouteServiceImpl implements RouteService {
return Result.fail("SCHEDULE_NOT_FOUND", "滚动班次不存在");
}
Integer beforeSold = schedule.getSoldSeats();
// 2. 查询库存
InventoryDO inventory = inventoryRepository.findByInventoryCode(schedule.getInventoryCode());
rollingScheduleRepository.update(
Wrappers.lambdaUpdate(RollingScheduleDO.class)
.eq(RollingScheduleDO::getRollingScheduleCode, dto.getRollingScheduleCode())
.setSql("sold_seats = sold_seats + " + dto.getQuantity())
if (inventory == null) {
return Result.fail("INVENTORY_NOT_FOUND", "库存不存在");
}
Integer beforeSold = inventory.getSoldStock();
// 3. 增加已售库存
inventory.setSoldStock(inventory.getSoldStock() + dto.getQuantity());
inventory.setUpdateTime(LocalDateTime.now());
inventoryRepository.save(inventory);
// 4. 记录库存日志
saveInventoryLog(
OrderTypeEnum.ROLLING.getCode(),
null,
dto.getRollingScheduleCode(),
schedule.getInventoryCode(),
InventoryOperationTypeEnum.DEDUCT.getCode(),
dto.getQuantity(),
beforeSold,
beforeSold + dto.getQuantity(),
dto.getOrderNo(),
"扣减库存(支付成功)"
);
// 记录库存日志
saveInventoryLog(OrderTypeEnum.ROLLING.getCode(), null, dto.getRollingScheduleCode(), InventoryOperationTypeEnum.DEDUCT.getCode(),
dto.getQuantity(), beforeSold, beforeSold + dto.getQuantity(),
dto.getOrderNo(), "扣减库存(支付成功)");
LogUtil.info("滚动班次库存扣减成功, rollingScheduleCode={}, quantity={}, orderNo={}",
dto.getRollingScheduleCode(), dto.getQuantity(), dto.getOrderNo());
LogUtil.info("滚动班次库存扣减成功, rollingScheduleCode={}, inventoryCode={}, quantity={}, orderNo={}",
dto.getRollingScheduleCode(), schedule.getInventoryCode(), dto.getQuantity(), dto.getOrderNo());
return Result.success(true);
}
private Result<Boolean> releaseRollingScheduleInventory(InventoryOperationDTO dto) {
// 1. 查询滚动班次
RollingScheduleDO schedule = rollingScheduleRepository.getOne(
Wrappers.lambdaQuery(RollingScheduleDO.class)
.eq(RollingScheduleDO::getRollingScheduleCode, dto.getRollingScheduleCode())
@@ -277,22 +380,37 @@ public class RouteServiceImpl implements RouteService {
return Result.fail("SCHEDULE_NOT_FOUND", "滚动班次不存在");
}
Integer beforeQty = schedule.getAvailableSeats();
// 2. 查询库存
InventoryDO inventory = inventoryRepository.findByInventoryCode(schedule.getInventoryCode());
// 释放库存
rollingScheduleRepository.update(
Wrappers.lambdaUpdate(RollingScheduleDO.class)
.eq(RollingScheduleDO::getRollingScheduleCode, dto.getRollingScheduleCode())
.setSql("available_seats = available_seats + " + dto.getQuantity())
if (inventory == null) {
return Result.fail("INVENTORY_NOT_FOUND", "库存不存在");
}
Integer beforeQty = inventory.getRemainingStock();
// 3. 释放库存(增加剩余库存)
inventory.setRemainingStock(inventory.getRemainingStock() + dto.getQuantity());
inventory.setUpdateTime(LocalDateTime.now());
inventoryRepository.save(inventory);
// 4. 记录库存日志
saveInventoryLog(
OrderTypeEnum.ROLLING.getCode(),
null,
dto.getRollingScheduleCode(),
schedule.getInventoryCode(),
InventoryOperationTypeEnum.RELEASE.getCode(),
dto.getQuantity(),
beforeQty,
beforeQty + dto.getQuantity(),
dto.getOrderNo(),
"释放库存(订单取消/超时)"
);
// 记录库存日志
saveInventoryLog(OrderTypeEnum.ROLLING.getCode(), null, dto.getRollingScheduleCode(), InventoryOperationTypeEnum.RELEASE.getCode(),
dto.getQuantity(), beforeQty, beforeQty + dto.getQuantity(),
dto.getOrderNo(), "释放库存(订单取消/超时)");
LogUtil.info("滚动班次库存释放成功, rollingScheduleCode={}, quantity={}, orderNo={}",
dto.getRollingScheduleCode(), dto.getQuantity(), dto.getOrderNo());
LogUtil.info("滚动班次库存释放成功, rollingScheduleCode={}, inventoryCode={}, quantity={}, orderNo={}",
dto.getRollingScheduleCode(), schedule.getInventoryCode(), dto.getQuantity(), dto.getOrderNo());
return Result.success(true);
}
@@ -300,13 +418,15 @@ public class RouteServiceImpl implements RouteService {
// ==================== 库存日志记录 ====================
private void saveInventoryLog(String inventoryType, String scheduleCode,
String rollingScheduleCode, String operationType,
Integer quantity, Integer beforeQty, Integer afterQty,
String rollingScheduleCode, String inventoryCode,
String operationType, Integer quantity,
Integer beforeQty, Integer afterQty,
String orderNo, String remark) {
InventoryLogDO inventoryLogDO = new InventoryLogDO();
inventoryLogDO.setInventoryType(inventoryType);
inventoryLogDO.setScheduleCode(scheduleCode);
inventoryLogDO.setRollingScheduleCode(rollingScheduleCode);
inventoryLogDO.setInventoryCode(inventoryCode);
inventoryLogDO.setOperationType(operationType);
inventoryLogDO.setQuantity(quantity);
inventoryLogDO.setBeforeQty(beforeQty);