From 49796f9f0b7599142629c56c1c689ab568b30141 Mon Sep 17 00:00:00 2001 From: menxipeng Date: Sat, 8 Nov 2025 12:37:58 +0800 Subject: [PATCH] =?UTF-8?q?=E8=AE=A2=E9=98=85?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../ruoyi/system/service/ShopUserService.java | 7 ++ .../service/impl/CShopUserServiceImpl.java | 81 ++++++++++++++ .../util/AppleNotificationProcessor.java | 104 +++++++++++++++++- 3 files changed, 191 insertions(+), 1 deletion(-) diff --git a/ruoyi-system/src/main/java/com/ruoyi/system/service/ShopUserService.java b/ruoyi-system/src/main/java/com/ruoyi/system/service/ShopUserService.java index 8271734..a478bb3 100644 --- a/ruoyi-system/src/main/java/com/ruoyi/system/service/ShopUserService.java +++ b/ruoyi-system/src/main/java/com/ruoyi/system/service/ShopUserService.java @@ -16,5 +16,12 @@ public interface ShopUserService { */ ShopUser updateShopUserVipTime(Long userId, String type); + /** + * 移除会员时间 + * @param userId + * @param type 1 - 月 2-季 3-半年 4-年 + */ + ShopUser updateShopUserRemoveVipTime(Long userId, String type); + ShopUser selectUserById(Long userId); } diff --git a/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/CShopUserServiceImpl.java b/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/CShopUserServiceImpl.java index 786d76f..e32b013 100644 --- a/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/CShopUserServiceImpl.java +++ b/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/CShopUserServiceImpl.java @@ -205,6 +205,87 @@ public class CShopUserServiceImpl implements ShopUserService { } } + @Override + public ShopUser updateShopUserRemoveVipTime(Long userId, String type) { + //* 移除会员时间 + // * @param userId + // * @param type 1 - 月 2-季 3-半年 4-年 + + // 根据type计算要移除的天数 + int days = 0; + switch (type) { + case "1": + days = 30; // 月 + break; + case "2": + days = 90; // 季 + break; + case "3": + days = 180; // 半年 + break; + case "4": + days = 365; // 年 + break; + default: + ShopUser errorMsg = new ShopUser(); + errorMsg.setMsg("VIP类型参数错误"); + return errorMsg; + } + + // 查询用户信息 + ShopUser shopUser = shopUserMapper.selectShopUserByUserId(userId); + if (shopUser == null) { + ShopUser errorMsg = new ShopUser(); + errorMsg.setMsg("用户不存在"); + return errorMsg; + } + + // 检查用户是否是VIP + if (shopUser.getVip() == null || shopUser.getVip() != 1L) { + ShopUser errorMsg = new ShopUser(); + errorMsg.setMsg("用户不是VIP,无法移除VIP时间"); + return errorMsg; + } + + // 检查VIP结束时间是否存在 + if (shopUser.getVipEndTime() == null) { + ShopUser errorMsg = new ShopUser(); + errorMsg.setMsg("VIP结束时间不存在"); + return errorMsg; + } + + Date currentDate = new Date(); + Calendar calendar = Calendar.getInstance(); + calendar.setTime(shopUser.getVipEndTime()); + calendar.add(Calendar.DAY_OF_YEAR, -days); // 减去天数 + Date newEndTime = calendar.getTime(); + + // 判断移除后的时间是否已过期 + if (newEndTime.before(currentDate) || newEndTime.equals(currentDate)) { + // VIP时间已过期或刚好到期,移除VIP标识 + shopUser.setVip(2L); // 设置为非VIP + shopUser.setVipStartTime(null); + shopUser.setVipEndTime(null); + } else { + // VIP时间还有剩余,只更新结束时间 + shopUser.setVipEndTime(newEndTime); + // 如果开始时间晚于新的结束时间,也需要调整开始时间 + if (shopUser.getVipStartTime() != null && shopUser.getVipStartTime().after(newEndTime)) { + shopUser.setVipStartTime(newEndTime); + } + } + + // 更新到数据库 + int updateCount = shopUserMapper.updateShopUser(shopUser); + if (updateCount > 0) { + return shopUser; + } else { + ShopUser errorMsg = new ShopUser(); + errorMsg.setMsg("VIP时间移除失败"); + return errorMsg; + } + } + @Override public ShopUser selectUserById(Long userId) { return shopUserMapper.selectShopUserByUserId(userId); diff --git a/ruoyi-system/src/main/java/com/ruoyi/system/util/AppleNotificationProcessor.java b/ruoyi-system/src/main/java/com/ruoyi/system/util/AppleNotificationProcessor.java index bd0df8d..cc69773 100644 --- a/ruoyi-system/src/main/java/com/ruoyi/system/util/AppleNotificationProcessor.java +++ b/ruoyi-system/src/main/java/com/ruoyi/system/util/AppleNotificationProcessor.java @@ -4,6 +4,7 @@ import com.alibaba.fastjson2.JSONObject; import com.ruoyi.common.utils.DateUtils; import com.ruoyi.common.utils.StringUtils; import com.ruoyi.common.core.domain.entity.OrderInfo; +import com.ruoyi.common.core.domain.entity.PayStatusEnum; import com.ruoyi.common.core.domain.entity.ShopUser; import com.ruoyi.system.mapper.OrderInfoMapper; import com.ruoyi.system.service.IOrderInfoService; @@ -370,8 +371,109 @@ public class AppleNotificationProcessor { RenewalInfo renewalInfo) { log.warn("处理退款事件 - 子类型: {}", notificationInfo.getSubtype()); - String transactionId = getOriginalTransactionId(transactionInfo, renewalInfo); + // 优先使用 transactionInfo 中的 transactionId,如果没有则使用 originalTransactionId + String transactionId = null; + String originalTransactionId = null; + if (transactionInfo != null) { + transactionId = transactionInfo.getTransactionId(); + originalTransactionId = transactionInfo.getOriginalTransactionId(); + } + + // 如果 transactionId 为空,尝试使用 originalTransactionId + if (StringUtils.isEmpty(transactionId)) { + transactionId = originalTransactionId; + } + + // 如果还是为空,尝试从 renewalInfo 获取 + if (StringUtils.isEmpty(transactionId) && renewalInfo != null) { + transactionId = renewalInfo.getOriginalTransactionId(); + } + + if (StringUtils.isEmpty(transactionId)) { + log.error("退款事件中交易ID为空,无法处理退款"); + return; + } + + // 1. 根据交易ID查找订单 + OrderInfo refundOrder = orderInfoMapper.selectByTradeNo(transactionId); + // if (refundOrder == null) { + // // 如果通过 transactionId 找不到,尝试通过 originalTransactionId 查找 + // if (StringUtils.isNotEmpty(originalTransactionId)) { + // OrderInfo queryOrder = new OrderInfo(); + // queryOrder.setCallbackContent(originalTransactionId); + // queryOrder.setPayType("applePay"); + // List orders = orderInfoService.selectOrderInfoList(queryOrder); + // if (orders != null && !orders.isEmpty()) { + // // 找到最新的订单(按创建时间倒序,取第一个) + // refundOrder = orders.stream() + // .filter(order -> order.getPackageType() != null) + // .findFirst() + // .orElse(null); + // } + // } + // } + + if (refundOrder == null) { + log.error("无法找到交易ID {} 对应的订单,无法处理退款", transactionId); + return; + } + + Long userId = refundOrder.getUserId(); + String packageType = refundOrder.getPackageType(); + + if (userId == null) { + log.error("订单中用户ID为空,无法处理退款。订单ID: {}", refundOrder.getOrderId()); + return; + } + + if (StringUtils.isEmpty(packageType)) { + log.error("订单中套餐类型为空,无法处理退款。订单ID: {}", refundOrder.getOrderId()); + return; + } + + // 2. 检查订单是否已退款(防止重复处理) + if (refundOrder.getPayStatus() != null && refundOrder.getPayStatus() == PayStatusEnum.REFUND.getStatus()) { + log.warn("订单已退款,跳过处理。订单ID: {}, 交易ID: {}", refundOrder.getOrderId(), transactionId); + return; + } + + // 3. 移除用户VIP时间 + try { + ShopUser updatedUser = shopUserService.updateShopUserRemoveVipTime(userId, packageType); + if (updatedUser != null && updatedUser.getMsg() == null) { + log.info("用户VIP时间移除成功,用户ID: {}, 套餐类型: {}", userId, packageType); + } else { + String errorMsg = updatedUser != null ? updatedUser.getMsg() : "未知错误"; + log.error("用户VIP时间移除失败,用户ID: {}, 错误信息: {}", userId, errorMsg); + // 即使VIP时间移除失败,也继续更新订单状态 + } + } catch (Exception e) { + log.error("移除用户VIP时间异常,用户ID: {}, 错误: {}", userId, e.getMessage(), e); + // 即使VIP时间移除失败,也继续更新订单状态 + } + + // 4. 更新订单状态为已退款 + try { + refundOrder.setPayStatus(PayStatusEnum.REFUND.getStatus()); // 4-已退款 + refundOrder.setRefundTime(DateUtils.getNowDate()); + // 如果订单金额存在,设置退款金额为订单金额(全额退款) + if (refundOrder.getAmount() != null) { + refundOrder.setRefundAmount(refundOrder.getAmount().longValue()); + } + refundOrder.setUpdateTime(DateUtils.getNowDate()); + + int updateResult = orderInfoService.updateOrderInfo(refundOrder); + if (updateResult > 0) { + log.info("退款订单更新成功,订单ID: {}, 交易ID: {}, 用户ID: {}", + refundOrder.getOrderId(), transactionId, userId); + } else { + log.error("退款订单更新失败,订单ID: {}, 交易ID: {}", refundOrder.getOrderId(), transactionId); + } + } catch (Exception e) { + log.error("更新退款订单状态异常,订单ID: {}, 交易ID: {}, 错误: {}", + refundOrder.getOrderId(), transactionId, e.getMessage(), e); + } } private void handleRevokeEvent(NotificationInfo notificationInfo,