feat(智能柜): 添加归还期限功能并实现逾期订单处理

- 在smart_cabinet表添加return_deadline字段记录归还期限
- 在SmartCabinetEntity和SmartCabinetDTO中添加对应字段
- 新增DeadlineOrderJob定时任务处理逾期订单
- 修改订单商品状态枚举和SQL查询逻辑
- 调整订单商品状态查询条件为不等于2
This commit is contained in:
dzq 2025-07-21 08:29:07 +08:00
parent 4b055dac24
commit 9f04fe0ce3
7 changed files with 175 additions and 4 deletions

View File

@ -0,0 +1,155 @@
package com.agileboot.admin.customize.service.job;
import cn.hutool.core.date.DateUtil;
import com.agileboot.domain.cabinet.cell.db.CabinetCellEntity;
import com.agileboot.domain.cabinet.cell.db.CabinetCellService;
import com.agileboot.domain.cabinet.smartCabinet.db.SmartCabinetEntity;
import com.agileboot.domain.cabinet.smartCabinet.db.SmartCabinetService;
import com.agileboot.domain.qywx.authCorpInfo.db.QyAuthCorpInfoEntity;
import com.agileboot.domain.shop.order.db.ShopOrderEntity;
import com.agileboot.domain.shop.order.db.ShopOrderGoodsEntity;
import com.agileboot.domain.shop.order.db.ShopOrderGoodsService;
import com.agileboot.domain.shop.order.db.ShopOrderService;
import com.agileboot.domain.shop.paymentOperationLog.PaymentOperationLogApplicationService;
import com.agileboot.domain.shop.paymentOperationLog.command.AddPaymentOperationLogCommand;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;
import java.util.Date;
import java.util.List;
@RequiredArgsConstructor
@Component
@Slf4j
public class DeadlineOrderJob {
private final ShopOrderService shopOrderService;
private final ShopOrderGoodsService shopOrderGoodsService;
private final CabinetCellService cabinetCellService;
private final SmartCabinetService smartCabinetService;
private final PaymentOperationLogApplicationService paymentOperationLogApplicationService;
/**
* 定时任务处理超过归还期限的订单商品
* 每天凌晨3点执行检查所有处于借出中状态的订单商品是否逾期并进行处理
*/
@Scheduled(cron = "0 50 * * * *") // 每小时第50分钟执行
@Transactional // 确保任务的原子性如果处理过程中出现异常数据不会被部分更新
public void markOverdueOrdersAndRemoveFromCabinet() {
log.info("开始执行逾期订单处理及商品下架任务...");
try {
// 1. 查询所有处于正常/借出中状态且关联了格口ID的订单商品
// 假设 ShopOrderGoodsEntity.STATUS_NORMAL_BORROWED = 1
// 并且只处理借还模式ShopOrderEntity.mode = 2的订单商品
// 仅选择 payStatus 2 (已支付) 的订单商品进行处理因为未支付的订单不应该算作借出
LambdaQueryWrapper<ShopOrderGoodsEntity> queryWrapper = new LambdaQueryWrapper<>();
queryWrapper.eq(ShopOrderGoodsEntity::getStatus, ShopOrderGoodsEntity.STATUS_NORMAL_BORROWED); // Assuming 1 means "borrowed"
queryWrapper.isNotNull(ShopOrderGoodsEntity::getCellId); // 必须在格口中
List<ShopOrderGoodsEntity> borrowedGoodsList = shopOrderGoodsService.list(queryWrapper);
if (CollectionUtils.isEmpty(borrowedGoodsList)) {
log.info("未找到需要检查的借出中商品记录.");
return;
}
log.info("查找到 {} 条需检查的借出中商品记录.", borrowedGoodsList.size());
for (ShopOrderGoodsEntity orderGoods : borrowedGoodsList) {
// 获取关联的订单信息
ShopOrderEntity order = shopOrderService.getById(orderGoods.getOrderId());
if (order == null) {
log.warn("订单商品[{}]关联的订单[{}]不存在,跳过处理.", orderGoods.getOrderGoodsId(), orderGoods.getOrderId());
continue;
}
// 确保是借还模式
if (order.getMode() != 0) { // 0-支付模式
continue;
}
// 确保订单已支付
if (order.getPayStatus() != 2) { // 2-已支付
log.debug("订单[{}]未支付,订单商品[{}]跳过处理.", order.getOrderId(), orderGoods.getOrderGoodsId());
continue;
}
// 获取关联的格口信息
CabinetCellEntity cabinetCell = cabinetCellService.getById(orderGoods.getCellId());
if (cabinetCell == null) {
log.warn("订单商品[{}]关联的格口[{}]不存在,跳过处理.", orderGoods.getOrderGoodsId(), orderGoods.getCellId());
continue;
}
if (!cabinetCell.getStock().equals(0)) {
log.warn("订单商品[{}]关联的格口[{}]库存不为0跳过处理.", orderGoods.getOrderGoodsId(), cabinetCell.getCellId());
continue;
}
// 获取关联的智能柜信息以获取归还期限
SmartCabinetEntity smartCabinet = smartCabinetService.getById(cabinetCell.getCabinetId());
if (smartCabinet == null) {
log.warn("格口[{}]关联的智能柜[{}]不存在,跳过处理.", cabinetCell.getCellId(), cabinetCell.getCabinetId());
continue;
}
Integer returnDeadlineDays = smartCabinet.getReturnDeadline();
// 检查归还期限是否有效大于0天
if (returnDeadlineDays == null || returnDeadlineDays <= 0) {
continue;
}
Date orderCreateTime = order.getCreateTime();
if (orderCreateTime == null) {
log.warn("订单[{}]的创建时间为空,无法计算归还期限,订单商品[{}]跳过处理.", order.getOrderId(), orderGoods.getOrderGoodsId());
continue;
}
// 计算归还截止日期
Date deadlineDate = DateUtil.offsetDay(orderCreateTime, returnDeadlineDays);
Date now = new Date(); // 当前时间
// 如果当前时间晚于归还截止日期则商品已逾期
if (now.after(deadlineDate)) {
log.info("发现逾期订单商品:订单号[{}], 商品ID[{}], 名称[{}]。创建时间[{}], 归还期限[{}天], 截止日期[{}].",
order.getOrderId(), orderGoods.getOrderGoodsId(), orderGoods.getGoodsName(),
DateUtil.formatDateTime(orderCreateTime), returnDeadlineDays, DateUtil.formatDateTime(deadlineDate));
// 1. 更新订单商品状态为已逾期
orderGoods.setStatus(ShopOrderGoodsEntity.STATUS_OVERDUE); // STATUS_OVERDUE = 7
// shopOrderGoodsService.updateById(orderGoods); // 更新数据库
// 2. 将商品从智能柜格口下架
cabinetCell.setGoodsId(null); // 清除关联商品ID
cabinetCell.setUsageStatus(1); // 使用状态改为1-空闲
// cabinetCellService.updateById(cabinetCell); // 更新数据库
log.info("成功处理逾期商品订单商品ID[{}]状态更新为已逾期并从格口ID[{}]下架。", orderGoods.getOrderGoodsId(), cabinetCell.getCellId());
try {
AddPaymentOperationLogCommand paymentOperationLogCommand = new AddPaymentOperationLogCommand();
paymentOperationLogCommand.setOperationType("DeadlineOrder");
paymentOperationLogCommand.setStatus(1);
paymentOperationLogCommand.setRemark(
String.format("逾期订单商品:订单号[%s], 商品ID[%s], 名称[%s]。创建时间[%s], 归还期限[%s天], 截止日期[%s].",
order.getOrderId(), orderGoods.getOrderGoodsId(), orderGoods.getGoodsName(), DateUtil.formatDateTime(orderCreateTime), returnDeadlineDays, DateUtil.formatDateTime(deadlineDate)));
paymentOperationLogCommand.initBaseEntity();
paymentOperationLogApplicationService.addPaymentOperationLog(paymentOperationLogCommand);
} catch (Exception e) {
log.error("处理逾期订单商品[{}]时创建退款操作日志失败.", orderGoods.getOrderGoodsId(), e);
}
}
}
} catch (Exception globalException) {
// 记录整个定时任务的全局错误
log.error("执行逾期订单处理及商品下架任务时发生全局错误:", globalException);
}
log.info("逾期订单处理及商品下架任务执行完毕.");
}
}

View File

@ -79,6 +79,10 @@ public class SmartCabinetEntity extends BaseEntity<SmartCabinetEntity> {
@TableField("location")
private Integer location;
@ApiModelProperty("归还期限0表示不限制")
@TableField("return_deadline")
private Integer returnDeadline;
@ApiModelProperty("已用格口数")
@TableField(exist = false)
private Integer usedCells;

View File

@ -62,6 +62,9 @@ public class SmartCabinetDTO {
@ExcelColumn(name = "柜机位置")
private Integer location;
@ExcelColumn(name = "归还期限0表示不限制")
private Integer returnDeadline;
@ExcelColumn(name = "已用格口数")
private Integer usedCells;

View File

@ -449,7 +449,7 @@ public class OrderApplicationService {
if (Integer.valueOf(1).equals(hasReturn)) {
orderGoodsQueryWrapper.eq("status", 2);
} else if (Integer.valueOf(0).equals(hasReturn)) {
orderGoodsQueryWrapper.eq("status", 1);
orderGoodsQueryWrapper.ne("status", 2);
}
// 根据查询条件获取订单商品列表
List<ShopOrderGoodsEntity> orderGoods = orderGoodsService.list(orderGoodsQueryWrapper);
@ -524,7 +524,7 @@ public class OrderApplicationService {
if (Integer.valueOf(1).equals(hasReturn)) {
orderGoodsQueryWrapper.eq("status", 2);
} else if (Integer.valueOf(0).equals(hasReturn)) {
orderGoodsQueryWrapper.eq("status", 1);
orderGoodsQueryWrapper.ne("status", 2);
}
List<ShopOrderGoodsEntity> orderGoods = orderGoodsService.list(orderGoodsQueryWrapper);

View File

@ -26,6 +26,14 @@ import lombok.Setter;
@ApiModel(value = "ShopOrderGoodsEntity对象", description = "订单商品明细表")
public class ShopOrderGoodsEntity extends BaseEntity<ShopOrderGoodsEntity> {
public static final Integer STATUS_NORMAL_BORROWED = 1;
public static final Integer STATUS_RETURNED = 2;
public static final Integer STATUS_EXCHANGED = 3;
public static final Integer STATUS_COMPLETED = 4;
public static final Integer STATUS_UNDER_REVIEW = 5;
public static final Integer STATUS_RETURN_REJECTED = 6;
public static final Integer STATUS_OVERDUE = 7;
private static final long serialVersionUID = 1L;
@ApiModelProperty("订单商品唯一ID")
@ -68,7 +76,7 @@ public class ShopOrderGoodsEntity extends BaseEntity<ShopOrderGoodsEntity> {
@TableField("cover_img")
private String coverImg;
@ApiModelProperty("商品状态1正常 2已退货 3已换货 4已完成 5审核中 6退货未通过")
@ApiModelProperty("商品状态1正常/借出中 2已退货 3已换货 4已完成 5审核中 6退货未通过 7已逾期")
@TableField("status")
private Integer status;

View File

@ -23,7 +23,7 @@ public interface ShopOrderMapper extends BaseMapper<ShopOrderEntity> {
@Select("SELECT o.*, " +
"GROUP_CONCAT(DISTINCT og.goods_name) AS goodsNames, " +
"GROUP_CONCAT(DISTINCT og.cover_img) AS coverImgs, " +
"CASE WHEN o.status = 2 AND MAX(CASE WHEN og.status = 1 THEN 1 ELSE 0 END) = 1 THEN 0 ELSE 1 END AS returnStatus " +
"CASE WHEN o.status = 2 AND MAX(CASE WHEN og.status = 2 THEN 0 ELSE 1 END) = 1 THEN 0 ELSE 1 END AS returnStatus " +
"FROM shop_order o " +
"LEFT JOIN shop_order_goods og ON o.order_id = og.order_id AND og.deleted = 0 " +
"LEFT JOIN cabinet_cell cc ON cc.cell_id = og.cell_id " +

1
sql/20250718.sql Normal file
View File

@ -0,0 +1 @@
ALTER TABLE `smart_cabinet` ADD COLUMN `return_deadline` INT NOT NULL DEFAULT 0 COMMENT '归还期限0表示不限制';