diff --git a/src/main/java/com/gxwebsoft/shop/config/OrderConfigProperties.java b/src/main/java/com/gxwebsoft/shop/config/OrderConfigProperties.java index 2d0ba07..9426e5f 100644 --- a/src/main/java/com/gxwebsoft/shop/config/OrderConfigProperties.java +++ b/src/main/java/com/gxwebsoft/shop/config/OrderConfigProperties.java @@ -33,6 +33,11 @@ public class OrderConfigProperties { */ private DefaultConfig defaultConfig = new DefaultConfig(); + /** + * 订单自动取消配置 + */ + private AutoCancel autoCancel = new AutoCancel(); + @Data public static class TestAccount { /** @@ -112,6 +117,71 @@ public class OrderConfigProperties { testAccount.getPhoneNumbers().contains(phone); } + @Data + public static class AutoCancel { + /** + * 是否启用自动取消功能 + */ + private boolean enabled = true; + + /** + * 默认超时时间(分钟) + */ + private Integer defaultTimeoutMinutes = 30; + + /** + * 定时任务检查间隔(分钟) + */ + private Integer checkIntervalMinutes = 5; + + /** + * 批量处理大小 + */ + private Integer batchSize = 100; + + /** + * 租户特殊配置 + */ + private List tenantConfigs; + } + + @Data + public static class TenantCancelConfig { + /** + * 租户ID + */ + private Integer tenantId; + + /** + * 租户名称 + */ + private String tenantName; + + /** + * 超时时间(分钟) + */ + private Integer timeoutMinutes; + + /** + * 是否启用 + */ + private boolean enabled = true; + } + + /** + * 获取指定租户的超时时间 + */ + public Integer getTimeoutMinutes(Integer tenantId) { + if (autoCancel.getTenantConfigs() != null) { + for (TenantCancelConfig config : autoCancel.getTenantConfigs()) { + if (config.isEnabled() && config.getTenantId().equals(tenantId)) { + return config.getTimeoutMinutes(); + } + } + } + return autoCancel.getDefaultTimeoutMinutes(); + } + /** * 获取租户规则 */ diff --git a/src/main/java/com/gxwebsoft/shop/controller/ShopOrderController.java b/src/main/java/com/gxwebsoft/shop/controller/ShopOrderController.java index b56c9c0..dbbce28 100644 --- a/src/main/java/com/gxwebsoft/shop/controller/ShopOrderController.java +++ b/src/main/java/com/gxwebsoft/shop/controller/ShopOrderController.java @@ -17,6 +17,8 @@ import com.gxwebsoft.common.system.entity.Payment; import com.gxwebsoft.shop.service.ShopOrderGoodsService; import com.gxwebsoft.shop.service.ShopOrderService; import com.gxwebsoft.shop.service.OrderBusinessService; +import com.gxwebsoft.shop.service.OrderCancelService; +import com.gxwebsoft.shop.task.OrderAutoCancelTask; import com.gxwebsoft.shop.entity.ShopOrder; import com.gxwebsoft.shop.param.ShopOrderParam; import com.gxwebsoft.shop.dto.OrderCreateRequest; @@ -36,6 +38,8 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Value; import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.security.core.Authentication; +import org.springframework.security.core.context.SecurityContextHolder; import org.springframework.web.bind.annotation.*; import javax.annotation.Resource; @@ -63,6 +67,10 @@ public class ShopOrderController extends BaseController { @Resource private OrderBusinessService orderBusinessService; @Resource + private OrderCancelService orderCancelService; + @Resource + private OrderAutoCancelTask orderAutoCancelTask; + @Resource private RedisUtil redisUtil; @Resource private ConfigProperties conf; @@ -214,6 +222,74 @@ public class ShopOrderController extends BaseController { return success(shopOrderService.total()); } + @Operation(summary = "取消订单") + @PutMapping("/cancel/{id}") + public ApiResult cancelOrder(@PathVariable("id") Integer id) { + try { + User loginUser = getLoginUser(); + if (loginUser == null) { + return fail("用户未登录"); + } + + ShopOrder order = shopOrderService.getById(id); + if (order == null) { + return fail("订单不存在"); + } + + // 检查订单是否属于当前用户(非管理员用户) + if (!loginUser.getUserId().equals(order.getUserId()) && + !hasOrderCancelAuthority()) { + return fail("无权限取消此订单"); + } + + // 检查订单状态 + if (order.getPayStatus() != null && order.getPayStatus()) { + return fail("订单已支付,无法取消"); + } + + if (order.getOrderStatus() != null && order.getOrderStatus() != 0) { + return fail("订单状态不允许取消"); + } + + boolean success = orderCancelService.cancelOrder(order); + if (success) { + return success("订单取消成功"); + } else { + return fail("订单取消失败"); + } + + } catch (Exception e) { + logger.error("取消订单失败,订单ID:{}", id, e); + return fail("取消订单失败:" + e.getMessage()); + } + } + + @PreAuthorize("hasAuthority('shop:shopOrder:manage')") + @Operation(summary = "手动触发订单自动取消任务(管理员)") + @PostMapping("/auto-cancel/trigger") + public ApiResult triggerAutoCancelTask() { + try { + orderAutoCancelTask.manualCancelExpiredOrders(); + return success("自动取消任务已触发"); + } catch (Exception e) { + logger.error("触发自动取消任务失败", e); + return fail("触发失败:" + e.getMessage()); + } + } + + @PreAuthorize("hasAuthority('shop:shopOrder:manage')") + @Operation(summary = "获取自动取消任务状态(管理员)") + @GetMapping("/auto-cancel/status") + public ApiResult getAutoCancelTaskStatus() { + try { + String status = orderAutoCancelTask.getTaskStatus(); + return success(status); + } catch (Exception e) { + logger.error("获取自动取消任务状态失败", e); + return fail("获取状态失败:" + e.getMessage()); + } + } + @Schema(description = "异步通知11") @PostMapping("/notify/{tenantId}") public String wxNotify(@RequestHeader Map header, @RequestBody String body, @PathVariable("tenantId") Integer tenantId) { @@ -379,4 +455,27 @@ public class ShopOrderController extends BaseController { return "fail"; } + /** + * 检查是否有订单取消权限 + */ + private boolean hasOrderCancelAuthority() { + try { + Authentication authentication = SecurityContextHolder.getContext().getAuthentication(); + if (authentication == null) { + return false; + } + + // 检查是否有管理员权限 + return authentication.getAuthorities().stream() + .anyMatch(authority -> + authority.getAuthority().equals("shop:shopOrder:cancel") || + authority.getAuthority().equals("shop:shopOrder:update") || + authority.getAuthority().equals("ROLE_ADMIN") || + authority.getAuthority().equals("shop:shopOrder:manage")); + } catch (Exception e) { + logger.warn("检查订单取消权限时发生异常", e); + return false; + } + } + } diff --git a/src/main/java/com/gxwebsoft/shop/entity/ShopOrder.java b/src/main/java/com/gxwebsoft/shop/entity/ShopOrder.java index 799586a..3ba9f36 100644 --- a/src/main/java/com/gxwebsoft/shop/entity/ShopOrder.java +++ b/src/main/java/com/gxwebsoft/shop/entity/ShopOrder.java @@ -206,6 +206,13 @@ public class ShopOrder implements Serializable { @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") private LocalDateTime refundApplyTime; + @Schema(description = "取消时间") + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") + private LocalDateTime cancelTime; + + @Schema(description = "取消原因") + private String cancelReason; + @Schema(description = "过期时间") @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") private LocalDateTime expirationTime; diff --git a/src/main/java/com/gxwebsoft/shop/service/OrderCancelService.java b/src/main/java/com/gxwebsoft/shop/service/OrderCancelService.java new file mode 100644 index 0000000..da40112 --- /dev/null +++ b/src/main/java/com/gxwebsoft/shop/service/OrderCancelService.java @@ -0,0 +1,65 @@ +package com.gxwebsoft.shop.service; + +import com.gxwebsoft.shop.entity.ShopOrder; + +import java.util.List; + +/** + * 订单取消服务接口 + * + * @author WebSoft + * @since 2025-01-26 + */ +public interface OrderCancelService { + + /** + * 取消单个订单 + * + * @param order 订单对象 + * @return 是否取消成功 + */ + boolean cancelOrder(ShopOrder order); + + /** + * 批量取消订单 + * + * @param orders 订单列表 + * @return 成功取消的订单数量 + */ + int batchCancelOrders(List orders); + + /** + * 查找超时的待付款订单 + * + * @param timeoutMinutes 超时时间(分钟) + * @param batchSize 批量大小 + * @return 超时订单列表 + */ + List findExpiredUnpaidOrders(Integer timeoutMinutes, Integer batchSize); + + /** + * 查找指定租户的超时订单 + * + * @param tenantId 租户ID + * @param timeoutMinutes 超时时间(分钟) + * @param batchSize 批量大小 + * @return 超时订单列表 + */ + List findExpiredUnpaidOrdersByTenant(Integer tenantId, Integer timeoutMinutes, Integer batchSize); + + /** + * 回退订单库存 + * + * @param order 订单对象 + * @return 是否回退成功 + */ + boolean restoreOrderStock(ShopOrder order); + + /** + * 退还订单优惠券 + * + * @param order 订单对象 + * @return 是否退还成功 + */ + boolean returnOrderCoupon(ShopOrder order); +} diff --git a/src/main/java/com/gxwebsoft/shop/service/impl/OrderCancelServiceImpl.java b/src/main/java/com/gxwebsoft/shop/service/impl/OrderCancelServiceImpl.java new file mode 100644 index 0000000..dd29b9b --- /dev/null +++ b/src/main/java/com/gxwebsoft/shop/service/impl/OrderCancelServiceImpl.java @@ -0,0 +1,226 @@ +package com.gxwebsoft.shop.service.impl; + +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.gxwebsoft.shop.entity.*; +import com.gxwebsoft.shop.service.*; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import java.time.LocalDateTime; +import java.util.ArrayList; +import java.util.List; + +/** + * 订单取消服务实现 + * + * @author WebSoft + * @since 2025-01-26 + */ +@Slf4j +@Service +public class OrderCancelServiceImpl implements OrderCancelService { + + @Autowired + private ShopOrderService shopOrderService; + + @Autowired + private ShopOrderGoodsService shopOrderGoodsService; + + @Autowired + private ShopGoodsService shopGoodsService; + + @Autowired + private ShopGoodsSkuService shopGoodsSkuService; + + @Autowired + private CouponStatusService couponStatusService; + + @Override + @Transactional(rollbackFor = Exception.class) + public boolean cancelOrder(ShopOrder order) { + try { + log.info("开始取消订单,订单号:{},订单ID:{}", order.getOrderNo(), order.getOrderId()); + + // 1. 检查订单状态 + if (order.getPayStatus() != null && order.getPayStatus()) { + log.warn("订单已支付,无法取消,订单号:{}", order.getOrderNo()); + return false; + } + + if (order.getOrderStatus() != null && order.getOrderStatus() != 0) { + log.warn("订单状态不是待支付,无法取消,订单号:{},当前状态:{}", order.getOrderNo(), order.getOrderStatus()); + return false; + } + + // 2. 更新订单状态为已取消 + order.setOrderStatus(2); // 2表示已取消 + order.setCancelTime(LocalDateTime.now()); + order.setCancelReason("系统自动取消(超时未支付)"); + + boolean updateSuccess = shopOrderService.updateById(order); + if (!updateSuccess) { + log.error("更新订单状态失败,订单号:{}", order.getOrderNo()); + return false; + } + + // 3. 回退库存 + boolean stockRestored = restoreOrderStock(order); + if (!stockRestored) { + log.error("回退库存失败,订单号:{}", order.getOrderNo()); + // 注意:这里不直接返回false,因为订单状态已经更新,需要记录错误但继续处理 + } + + // 4. 退还优惠券 + boolean couponReturned = returnOrderCoupon(order); + if (!couponReturned) { + log.error("退还优惠券失败,订单号:{}", order.getOrderNo()); + // 同样不直接返回false + } + + log.info("订单取消成功,订单号:{},库存回退:{},优惠券退还:{}", + order.getOrderNo(), stockRestored, couponReturned); + return true; + + } catch (Exception e) { + log.error("取消订单失败,订单号:{}", order.getOrderNo(), e); + throw e; // 重新抛出异常,触发事务回滚 + } + } + + @Override + @Transactional(rollbackFor = Exception.class) + public int batchCancelOrders(List orders) { + if (orders == null || orders.isEmpty()) { + return 0; + } + + int successCount = 0; + for (ShopOrder order : orders) { + try { + if (cancelOrder(order)) { + successCount++; + } + } catch (Exception e) { + log.error("批量取消订单时发生错误,订单号:{}", order.getOrderNo(), e); + // 继续处理下一个订单 + } + } + + log.info("批量取消订单完成,总数:{},成功:{}", orders.size(), successCount); + return successCount; + } + + @Override + public List findExpiredUnpaidOrders(Integer timeoutMinutes, Integer batchSize) { + LocalDateTime expireTime = LocalDateTime.now().minusMinutes(timeoutMinutes); + + LambdaQueryWrapper queryWrapper = new LambdaQueryWrapper() + .eq(ShopOrder::getPayStatus, false) // 未支付 + .eq(ShopOrder::getOrderStatus, 0) // 待支付状态 + .lt(ShopOrder::getCreateTime, expireTime) // 创建时间小于过期时间 + .orderByAsc(ShopOrder::getCreateTime) + .last("LIMIT " + batchSize); + + return shopOrderService.list(queryWrapper); + } + + @Override + public List findExpiredUnpaidOrdersByTenant(Integer tenantId, Integer timeoutMinutes, Integer batchSize) { + LocalDateTime expireTime = LocalDateTime.now().minusMinutes(timeoutMinutes); + + LambdaQueryWrapper queryWrapper = new LambdaQueryWrapper() + .eq(ShopOrder::getTenantId, tenantId) + .eq(ShopOrder::getPayStatus, false) // 未支付 + .eq(ShopOrder::getOrderStatus, 0) // 待支付状态 + .lt(ShopOrder::getCreateTime, expireTime) // 创建时间小于过期时间 + .orderByAsc(ShopOrder::getCreateTime) + .last("LIMIT " + batchSize); + + return shopOrderService.list(queryWrapper); + } + + @Override + public boolean restoreOrderStock(ShopOrder order) { + try { + // 获取订单商品信息 + List orderGoods = shopOrderGoodsService.list( + new LambdaQueryWrapper() + .eq(ShopOrderGoods::getOrderId, order.getOrderId()) + ); + + if (orderGoods == null || orderGoods.isEmpty()) { + log.warn("订单没有商品信息,订单号:{}", order.getOrderNo()); + return true; // 没有商品信息也算成功 + } + + for (ShopOrderGoods orderGood : orderGoods) { + if (orderGood.getSkuId() != null && orderGood.getSkuId() > 0) { + // 多规格商品,恢复SKU库存 + restoreSkuStock(orderGood); + } else { + // 单规格商品,恢复商品库存 + restoreGoodsStock(orderGood); + } + } + + log.info("订单库存回退成功,订单号:{},商品数量:{}", order.getOrderNo(), orderGoods.size()); + return true; + + } catch (Exception e) { + log.error("回退订单库存失败,订单号:{}", order.getOrderNo(), e); + return false; + } + } + + @Override + public boolean returnOrderCoupon(ShopOrder order) { + try { + if (order.getCouponId() == null || order.getCouponId() <= 0) { + log.debug("订单未使用优惠券,订单号:{}", order.getOrderNo()); + return true; // 没有使用优惠券也算成功 + } + + boolean success = couponStatusService.returnCoupon(order.getOrderId()); + if (success) { + log.info("订单优惠券退还成功,订单号:{},优惠券ID:{}", order.getOrderNo(), order.getCouponId()); + } else { + log.warn("订单优惠券退还失败,订单号:{},优惠券ID:{}", order.getOrderNo(), order.getCouponId()); + } + return success; + + } catch (Exception e) { + log.error("退还订单优惠券失败,订单号:{}", order.getOrderNo(), e); + return false; + } + } + + /** + * 恢复SKU库存 + */ + private void restoreSkuStock(ShopOrderGoods orderGoods) { + ShopGoodsSku sku = shopGoodsSkuService.getById(orderGoods.getSkuId()); + if (sku != null) { + int newStock = (sku.getStock() != null ? sku.getStock() : 0) + orderGoods.getTotalNum(); + sku.setStock(newStock); + shopGoodsSkuService.updateById(sku); + log.debug("恢复SKU库存 - SKU ID:{},恢复数量:{},当前库存:{}", + orderGoods.getSkuId(), orderGoods.getTotalNum(), newStock); + } + } + + /** + * 恢复商品库存 + */ + private void restoreGoodsStock(ShopOrderGoods orderGoods) { + ShopGoods goods = shopGoodsService.getById(orderGoods.getGoodsId()); + if (goods != null) { + int newStock = (goods.getStock() != null ? goods.getStock() : 0) + orderGoods.getTotalNum(); + goods.setStock(newStock); + shopGoodsService.updateById(goods); + log.debug("恢复商品库存 - 商品ID:{},恢复数量:{},当前库存:{}", + orderGoods.getGoodsId(), orderGoods.getTotalNum(), newStock); + } + } +} diff --git a/src/main/java/com/gxwebsoft/shop/task/OrderAutoCancelTask.java b/src/main/java/com/gxwebsoft/shop/task/OrderAutoCancelTask.java new file mode 100644 index 0000000..55c1f2b --- /dev/null +++ b/src/main/java/com/gxwebsoft/shop/task/OrderAutoCancelTask.java @@ -0,0 +1,193 @@ +package com.gxwebsoft.shop.task; + +import com.gxwebsoft.shop.config.OrderConfigProperties; +import com.gxwebsoft.shop.entity.ShopOrder; +import com.gxwebsoft.shop.service.OrderCancelService; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; +import org.springframework.scheduling.annotation.Scheduled; +import org.springframework.stereotype.Component; + +import java.util.List; + +/** + * 订单自动取消定时任务 + * + * @author WebSoft + * @since 2025-01-26 + */ +@Slf4j +@Component +@ConditionalOnProperty(prefix = "shop.order.auto-cancel", name = "enabled", havingValue = "true", matchIfMissing = true) +public class OrderAutoCancelTask { + + @Autowired + private OrderCancelService orderCancelService; + + @Autowired + private OrderConfigProperties orderConfig; + + @Value("${spring.profiles.active:dev}") + private String activeProfile; + + /** + * 自动取消超时订单 + * 生产环境:每5分钟执行一次 + * 开发环境:每1分钟执行一次(便于测试) + */ + @Scheduled(cron = "${shop.order.auto-cancel.cron:0 */5 * * * ?}") + public void cancelExpiredOrders() { + if (!orderConfig.getAutoCancel().isEnabled()) { + log.debug("订单自动取消功能已禁用"); + return; + } + + log.info("开始执行订单自动取消任务..."); + + try { + long startTime = System.currentTimeMillis(); + int totalCancelledCount = 0; + + // 处理默认配置的订单 + int defaultCancelledCount = processDefaultTimeoutOrders(); + totalCancelledCount += defaultCancelledCount; + + // 处理租户特殊配置的订单 + int tenantCancelledCount = processTenantSpecificOrders(); + totalCancelledCount += tenantCancelledCount; + + long endTime = System.currentTimeMillis(); + long duration = endTime - startTime; + + log.info("订单自动取消任务完成,总取消数量: {},默认配置: {},租户配置: {},耗时: {}ms", + totalCancelledCount, defaultCancelledCount, tenantCancelledCount, duration); + + // 开发环境输出更详细的日志 + if ("dev".equals(activeProfile)) { + log.debug("开发环境 - 订单自动取消详情: 总共取消{}个订单", totalCancelledCount); + } + + } catch (Exception e) { + log.error("订单自动取消任务执行失败", e); + } + } + + /** + * 处理使用默认超时配置的订单 + */ + private int processDefaultTimeoutOrders() { + try { + Integer defaultTimeout = orderConfig.getAutoCancel().getDefaultTimeoutMinutes(); + Integer batchSize = orderConfig.getAutoCancel().getBatchSize(); + + log.debug("处理默认超时订单,超时时间: {}分钟,批量大小: {}", defaultTimeout, batchSize); + + List expiredOrders = orderCancelService.findExpiredUnpaidOrders(defaultTimeout, batchSize); + + if (expiredOrders.isEmpty()) { + log.debug("没有找到使用默认配置的超时订单"); + return 0; + } + + // 过滤掉有特殊租户配置的订单 + List ordersToCancel = filterOrdersWithoutTenantConfig(expiredOrders); + + if (ordersToCancel.isEmpty()) { + log.debug("过滤后没有需要使用默认配置取消的订单"); + return 0; + } + + int cancelledCount = orderCancelService.batchCancelOrders(ordersToCancel); + log.info("默认配置取消订单完成,找到: {}个,过滤后: {}个,成功取消: {}个", + expiredOrders.size(), ordersToCancel.size(), cancelledCount); + + return cancelledCount; + + } catch (Exception e) { + log.error("处理默认超时订单失败", e); + return 0; + } + } + + /** + * 处理租户特殊配置的订单 + */ + private int processTenantSpecificOrders() { + try { + List tenantConfigs = orderConfig.getAutoCancel().getTenantConfigs(); + if (tenantConfigs == null || tenantConfigs.isEmpty()) { + log.debug("没有配置租户特殊超时规则"); + return 0; + } + + int totalCancelledCount = 0; + Integer batchSize = orderConfig.getAutoCancel().getBatchSize(); + + for (OrderConfigProperties.TenantCancelConfig tenantConfig : tenantConfigs) { + if (!tenantConfig.isEnabled()) { + log.debug("租户{}的自动取消功能已禁用", tenantConfig.getTenantId()); + continue; + } + + log.debug("处理租户{}的超时订单,超时时间: {}分钟", + tenantConfig.getTenantId(), tenantConfig.getTimeoutMinutes()); + + List tenantExpiredOrders = orderCancelService.findExpiredUnpaidOrdersByTenant( + tenantConfig.getTenantId(), tenantConfig.getTimeoutMinutes(), batchSize); + + if (!tenantExpiredOrders.isEmpty()) { + int cancelledCount = orderCancelService.batchCancelOrders(tenantExpiredOrders); + totalCancelledCount += cancelledCount; + + log.info("租户{}取消订单完成,找到: {}个,成功取消: {}个", + tenantConfig.getTenantId(), tenantExpiredOrders.size(), cancelledCount); + } + } + + return totalCancelledCount; + + } catch (Exception e) { + log.error("处理租户特殊配置订单失败", e); + return 0; + } + } + + /** + * 过滤掉有租户特殊配置的订单 + */ + private List filterOrdersWithoutTenantConfig(List orders) { + List tenantConfigs = orderConfig.getAutoCancel().getTenantConfigs(); + if (tenantConfigs == null || tenantConfigs.isEmpty()) { + return orders; + } + + return orders.stream() + .filter(order -> { + // 检查该订单的租户是否有特殊配置 + return tenantConfigs.stream() + .noneMatch(config -> config.isEnabled() && config.getTenantId().equals(order.getTenantId())); + }) + .collect(java.util.stream.Collectors.toList()); + } + + /** + * 手动触发订单自动取消任务(用于测试) + */ + public void manualCancelExpiredOrders() { + log.info("手动触发订单自动取消任务..."); + cancelExpiredOrders(); + } + + /** + * 获取任务状态信息 + */ + public String getTaskStatus() { + return String.format("订单自动取消任务状态 - 启用: %s, 默认超时: %d分钟, 检查间隔: %d分钟, 批量大小: %d", + orderConfig.getAutoCancel().isEnabled(), + orderConfig.getAutoCancel().getDefaultTimeoutMinutes(), + orderConfig.getAutoCancel().getCheckIntervalMinutes(), + orderConfig.getAutoCancel().getBatchSize()); + } +} diff --git a/src/main/resources/application.yml b/src/main/resources/application.yml index be2cd44..665b992 100644 --- a/src/main/resources/application.yml +++ b/src/main/resources/application.yml @@ -139,6 +139,34 @@ shop: min-order-amount: 0 order-timeout-minutes: 30 + # 订单自动取消配置 + auto-cancel: + # 是否启用自动取消功能 + enabled: true + # 默认超时时间(分钟) + default-timeout-minutes: 30 + # 定时任务检查间隔(分钟) + check-interval-minutes: 5 + # 批量处理大小 + batch-size: 100 + # 定时任务执行时间(cron表达式) + # 生产环境:每5分钟执行一次 + # 开发环境:每1分钟执行一次(便于测试) + cron: "0 */5 * * * ?" + # 开发环境可以设置为: "0 */1 * * * ?" + + # 租户特殊配置 + tenant-configs: + - tenant-id: 10324 + tenant-name: "百色中学" + timeout-minutes: 60 # 捐款订单给更长的支付时间 + enabled: true + # 可以添加更多租户配置 + # - tenant-id: 10550 + # tenant-name: "其他租户" + # timeout-minutes: 15 + # enabled: true + # 证书配置 certificate: # 证书加载模式: CLASSPATH, FILESYSTEM, VOLUME