From 2b25ac503c92d10b198c055df6ad00431612dc2d Mon Sep 17 00:00:00 2001 From: chen-xin-zhi <3588068430@qq.com> Date: Fri, 14 Feb 2025 16:21:35 +0800 Subject: [PATCH] =?UTF-8?q?=E6=9B=B4=E6=96=B0=E4=BA=86=E6=9C=8D=E5=8A=A1?= =?UTF-8?q?=E7=B1=BB=E8=AE=A2=E5=8D=95=E6=A8=A1=E5=9D=97?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../controller/wx/WeChatPayController.java | 30 +++ .../model/entity/PendingServiceGood.java | 3 + .../model/entity/PendingServiceOrder.java | 3 + .../service/order/impl/OrderServiceImpl.java | 4 +- .../heritage/service/wx/WeChatService.java | 11 ++ .../service/wx/impl/WeChatServiceImpl.java | 176 ++++++++++++++---- 6 files changed, 194 insertions(+), 33 deletions(-) diff --git a/src/main/java/com/cultural/heritage/controller/wx/WeChatPayController.java b/src/main/java/com/cultural/heritage/controller/wx/WeChatPayController.java index 23cefc0..1147ebb 100644 --- a/src/main/java/com/cultural/heritage/controller/wx/WeChatPayController.java +++ b/src/main/java/com/cultural/heritage/controller/wx/WeChatPayController.java @@ -37,6 +37,7 @@ import java.io.IOException; @RestController @Tag(name = "微信支付接口") @RequestMapping("/wechat") +@Transactional(rollbackFor = Exception.class) public class WeChatPayController { @Resource @@ -108,6 +109,12 @@ public class WeChatPayController { } + + + + + + /** * Web管理员部分退款 * @param commonRequest 订单明细id @@ -127,6 +134,29 @@ public class WeChatPayController { } + + /** + * Web管理员剩余部分退款 + * @param commonRequest 订单id + */ + @PostMapping("/refund/rest/create") + @AuthCheck(mustRole = UserConstant.ADMIN_ROLE) + public BaseResponse createRestRefund(@RequestBody CommonRequest commonRequest) { + if (commonRequest == null || commonRequest.getId() <= 0) { + throw new BusinessException(ErrorCode.PARAMS_ERROR); + } + Long orderId = commonRequest.getId(); + Order order = ordersService.getById(orderId); + ThrowUtils.throwIf(order == null, ErrorCode.OPERATION_ERROR, "订单不存在"); + + Refund refund = weChatService.refundRestPayment(String.valueOf(orderId), order.getTotalAmount()); + return ResultUtils.success(refund); + } + + + + + /** * 全额退款回调 */ diff --git a/src/main/java/com/cultural/heritage/model/entity/PendingServiceGood.java b/src/main/java/com/cultural/heritage/model/entity/PendingServiceGood.java index 3a898a4..705b8be 100644 --- a/src/main/java/com/cultural/heritage/model/entity/PendingServiceGood.java +++ b/src/main/java/com/cultural/heritage/model/entity/PendingServiceGood.java @@ -1,5 +1,7 @@ package com.cultural.heritage.model.entity; +import com.baomidou.mybatisplus.annotation.IdType; +import com.baomidou.mybatisplus.annotation.TableId; import com.baomidou.mybatisplus.annotation.TableName; import lombok.Data; @@ -19,6 +21,7 @@ public class PendingServiceGood implements Serializable { /** * 服务类商品待处理id */ + @TableId(type = IdType.AUTO) private Long id; diff --git a/src/main/java/com/cultural/heritage/model/entity/PendingServiceOrder.java b/src/main/java/com/cultural/heritage/model/entity/PendingServiceOrder.java index aa899f9..b0878c1 100644 --- a/src/main/java/com/cultural/heritage/model/entity/PendingServiceOrder.java +++ b/src/main/java/com/cultural/heritage/model/entity/PendingServiceOrder.java @@ -1,5 +1,7 @@ package com.cultural.heritage.model.entity; +import com.baomidou.mybatisplus.annotation.IdType; +import com.baomidou.mybatisplus.annotation.TableId; import com.baomidou.mybatisplus.annotation.TableName; import lombok.Data; @@ -20,6 +22,7 @@ public class PendingServiceOrder implements Serializable { /** * 服务类订单待处理id */ + @TableId(type = IdType.AUTO) private Long id; diff --git a/src/main/java/com/cultural/heritage/service/order/impl/OrderServiceImpl.java b/src/main/java/com/cultural/heritage/service/order/impl/OrderServiceImpl.java index f041a1b..3a253bc 100644 --- a/src/main/java/com/cultural/heritage/service/order/impl/OrderServiceImpl.java +++ b/src/main/java/com/cultural/heritage/service/order/impl/OrderServiceImpl.java @@ -156,7 +156,7 @@ public class OrderServiceImpl extends ServiceImpl implements ThrowUtils.throwIf(orderTypeEnum == null, ErrorCode.PARAMS_ERROR); AddressSnapshot addressSnapshot = null; ContactsSnapshot contactsSnapshot = null; - CouponSnapshot couponSnapshot = new CouponSnapshot(); + CouponSnapshot couponSnapshot = null; // 获取订单地址信息 if (orderTypeEnum.equals(GoodTypeEnum.PRODUCT)) { @@ -171,7 +171,9 @@ public class OrderServiceImpl extends ServiceImpl implements UserCoupon userCoupon = userCouponService.getById(couponId); ThrowUtils.throwIf(userCoupon == null || userCoupon.getCouponVO().getStatus().equals("已过期"), ErrorCode.OPERATION_ERROR, "用户优惠券不存在或者已过期"); CouponVO couponVO = userCoupon.getCouponVO(); + couponSnapshot = new CouponSnapshot(); BeanUtils.copyProperties(couponVO, couponSnapshot); + couponSnapshot.setId(couponId); } // 封装订单明细信息 List orderItemAddRequestList = orderItemMainInfoAddRequestList.stream().map(orderItemMainInfoAddRequest -> { diff --git a/src/main/java/com/cultural/heritage/service/wx/WeChatService.java b/src/main/java/com/cultural/heritage/service/wx/WeChatService.java index 705ae74..165847f 100644 --- a/src/main/java/com/cultural/heritage/service/wx/WeChatService.java +++ b/src/main/java/com/cultural/heritage/service/wx/WeChatService.java @@ -40,6 +40,11 @@ public interface WeChatService { */ Refund refundPartPayment(String orderItemsId, BigDecimal amount); + /** + * 剩余退款申请 + */ + Refund refundRestPayment(String orderId, BigDecimal totalAmount); + /** * 获取退款回调信息 */ @@ -55,6 +60,12 @@ public interface WeChatService { */ boolean refundPartCallback(RefundNotification refundNotification); + + /** + * 剩余退款回调 + */ + boolean refundRestCallback(RefundNotification refundNotification); + // /** // * 发送订阅模板消息 // */ diff --git a/src/main/java/com/cultural/heritage/service/wx/impl/WeChatServiceImpl.java b/src/main/java/com/cultural/heritage/service/wx/impl/WeChatServiceImpl.java index fc14c05..26ebadb 100644 --- a/src/main/java/com/cultural/heritage/service/wx/impl/WeChatServiceImpl.java +++ b/src/main/java/com/cultural/heritage/service/wx/impl/WeChatServiceImpl.java @@ -8,10 +8,12 @@ import com.cultural.heritage.common.ErrorCode; import com.cultural.heritage.config.WxOpenConfig; import com.cultural.heritage.config.WxPayConfig; import com.cultural.heritage.constant.OrderStatusConstant; +import com.cultural.heritage.exception.BusinessException; import com.cultural.heritage.exception.ThrowUtils; import com.cultural.heritage.model.dto.snapshot.CouponSnapshot; import com.cultural.heritage.model.dto.snapshot.GoodSnapshot; import com.cultural.heritage.model.entity.*; +import com.cultural.heritage.service.common.CommonService; import com.cultural.heritage.service.good.AppointmentDateService; import com.cultural.heritage.service.good.GoodService; import com.cultural.heritage.service.order.*; @@ -77,6 +79,9 @@ public class WeChatServiceImpl implements WeChatService { @Resource private PendingServiceOrderService pendingServiceOrderService; + @Resource + private CommonService commonService; + /** * 请求参数 @@ -179,6 +184,7 @@ public class WeChatServiceImpl implements WeChatService { System.out.println("退款请求:" + createRequest); Refund refund = wxPayConfig.getRefundService().create(createRequest); System.out.println("退款申请结果:" + refund); + return refund; } @@ -194,8 +200,8 @@ public class WeChatServiceImpl implements WeChatService { public synchronized boolean refundCallback(RefundNotification refundNotification) { System.out.println("---------------------------微信退款回调(开始)-------------------------------"); // 获取订单信息 - String orderIdByString = refundNotification.getOutTradeNo(); - Order order = getOrderInfoByOrderNumber(orderIdByString); + String orderNumber = refundNotification.getOutTradeNo(); + Order order = getOrderInfoByOrderNumber(orderNumber); // 修改订单状态 modifyOrderStatus(order, OrderStatusConstant.PAYMENT_REFUNDED); @@ -209,7 +215,7 @@ public class WeChatServiceImpl implements WeChatService { updatePendingServiceOrder(order.getOrderNumber(), OrderStatusConstant.PAYMENT_REFUNDED); } else { // 恢复商品库存 - recoverGoodInventory(String.valueOf(order.getId())); + recoverGoodInventory(order); } System.out.println("---------------------------微信退款回调(结束)-------------------------------"); return true; @@ -230,7 +236,7 @@ public class WeChatServiceImpl implements WeChatService { Order order = orderService.getById(orderItems.getOrderId()); ThrowUtils.throwIf(order == null, ErrorCode.OPERATION_ERROR, "订单不存在"); // 判断该订单明细是否已经退款 - checkOrderItemStatus(orderItemsId); + checkOrderItemStatus(orderItemsId, order); String orderNumber = order.getOrderNumber(); // 退款请求 @@ -299,6 +305,78 @@ public class WeChatServiceImpl implements WeChatService { boolean update = goodService.updateById(good); ThrowUtils.throwIf(!update, ErrorCode.OPERATION_ERROR, "商品库存恢复失败"); } + System.out.println("---------------------------微信退款回调(结束)-------------------------------"); + return true; + } + + + + + /** + * 剩余退款申请 + */ + @Override + public Refund refundRestPayment(String orderId, BigDecimal totalAmount) { + // 获取订单号 + Order order = orderService.getById(orderId); + ThrowUtils.throwIf(order == null, ErrorCode.OPERATION_ERROR, "该订单不存在"); + String orderNumber = order.getOrderNumber(); + // 退款请求 + CreateRequest createRequest = new CreateRequest(); + // 商户订单号 + createRequest.setOutTradeNo(orderNumber); + // 商户退款单号 + String outRefundNo = RefundUtils.generateRefundNo(); + createRequest.setOutRefundNo(outRefundNo); + // 退款结果回调 + createRequest.setNotifyUrl(wxPayConfig.getNotifyUrl() + "/api/wechat/refund/callback"); + // 退款金额 + AmountReq amountReq = new AmountReq(); + long refundAmount = totalAmount.movePointRight(2).intValue(); + + // 获取剩余退款的金额 + BigDecimal restRefundAmount = this.getRestRefundAmount(order); + + amountReq.setRefund(restRefundAmount.movePointRight(2).longValue()); + amountReq.setTotal(refundAmount); + amountReq.setCurrency("CNY"); + createRequest.setAmount(amountReq); + // 申请退款 + System.out.println("退款请求:" + createRequest); + Refund refund = wxPayConfig.getRefundService().create(createRequest); + System.out.println("退款申请结果:" + refund); + + return refund; + } + + + + /** + * 剩余退款回调 + */ + @Override + public boolean refundRestCallback(RefundNotification refundNotification) { + + System.out.println("---------------------------微信退款回调(开始)-------------------------------"); + // 获取订单信息 + String orderNumber = refundNotification.getOutTradeNo(); + Order order = getOrderInfoByOrderNumber(orderNumber); + + // 修改订单状态 + modifyOrderStatus(order, OrderStatusConstant.PAYMENT_REFUNDED); + + // 生成退款记录 + createRefundRecord(refundNotification); + + boolean isGeneral = orderService.isGeneralGood(order.getOrderType()); + if (!isGeneral) { + // 更新服务类订单待处理记录 + updatePendingServiceOrder(order.getOrderNumber(), OrderStatusConstant.PAYMENT_REFUNDED); + } else { + // 恢复商品库存 + recoverGoodInventory(order); + } + System.out.println("---------------------------微信退款回调(结束)-------------------------------"); return true; } @@ -324,40 +402,48 @@ public class WeChatServiceImpl implements WeChatService { - - - - - - - - - - - - - - - + /** + * 获取剩余退款的金额 + */ + private BigDecimal getRestRefundAmount(Order order) { + QueryWrapper queryWrapper = new QueryWrapper<>(); + queryWrapper.eq("outTradeNo", order.getOrderNumber()); + List refundRecordList = refundRecordService.list(queryWrapper); + BigDecimal totalRefund = new BigDecimal("0.00"); + for (RefundRecord refundRecord : refundRecordList) { + totalRefund = totalRefund.add(refundRecord.getRefundAmount()); + } + return order.getTotalAmount().subtract(totalRefund); + } /** * 判断当前订单明细是否已退款 */ - public void checkOrderItemStatus(String orderItemsId) { - QueryWrapper pendingServiceOrderQueryWrapper = new QueryWrapper<>(); - pendingServiceOrderQueryWrapper.eq("orderItemId", orderItemsId); - PendingServiceOrder pendingServiceOrder = pendingServiceOrderService.getOne(pendingServiceOrderQueryWrapper); - ThrowUtils.throwIf(pendingServiceOrder == null || !pendingServiceOrder.getOrderItemStatus() - .equals(OrderStatusConstant.PENDING_SHIPMENT), ErrorCode.OPERATION_ERROR, "服务类订单待处理记录不存在或者当前订单明细状态错误"); + private void checkOrderItemStatus(String orderItemsId, Order order) { + boolean isGeneral = orderService.isGeneralGood(order.getOrderType()); + if (isGeneral) { + QueryWrapper queryWrapper = new QueryWrapper<>(); + queryWrapper.eq("outTradeNo", order.getOrderNumber()); + List refundRecordList = refundRecordService.list(queryWrapper); + for (RefundRecord refundRecord : refundRecordList) { + String itemId = RefundUtils.parseRefundNoToItemId(refundRecord.getOutRefundNo()); + System.out.println("订单明细id----------------------------------------------------------------------------------------------------->" + itemId); + if (orderItemsId.equals(itemId)) throw new BusinessException(ErrorCode.PARAMS_ERROR, "当前订单明细已退款"); + } + } else { + QueryWrapper pendingServiceOrderQueryWrapper = new QueryWrapper<>(); + pendingServiceOrderQueryWrapper.eq("orderItemId", orderItemsId); + PendingServiceOrder pendingServiceOrder = pendingServiceOrderService.getOne(pendingServiceOrderQueryWrapper); + ThrowUtils.throwIf(pendingServiceOrder == null || !pendingServiceOrder.getOrderItemStatus() + .equals(OrderStatusConstant.PENDING_SHIPMENT), ErrorCode.OPERATION_ERROR, "服务类订单待处理记录不存在或者当前订单明细状态错误"); + } } - - /** * 计算部分退款金额 */ @@ -399,6 +485,7 @@ public class WeChatServiceImpl implements WeChatService { + /** * 更新服务类商品订单待处理记录 */ @@ -441,7 +528,7 @@ public class WeChatServiceImpl implements WeChatService { RefundRecord refundRecord = new RefundRecord(); refundRecord.setOutTradeNo(refundNotification.getOutTradeNo()); refundRecord.setOutRefundNo(refundNotification.getOutRefundNo()); - refundRecord.setRefundAmount(BigDecimal.valueOf(refundNotification.getAmount().getRefund())); + refundRecord.setRefundAmount(BigDecimal.valueOf(refundNotification.getAmount().getRefund()).movePointLeft(2)); boolean save = refundRecordService.save(refundRecord); ThrowUtils.throwIf(!save, ErrorCode.OPERATION_ERROR, "退款记录生成失败"); @@ -449,6 +536,20 @@ public class WeChatServiceImpl implements WeChatService { + /** + * 生成退款记录 + */ + private void createRefundRecord(String outTradeNo, String outRefundNo, long refundAmount) { + RefundRecord refundRecord = new RefundRecord(); + refundRecord.setOutTradeNo(outTradeNo); + refundRecord.setOutRefundNo(outRefundNo); + refundRecord.setRefundAmount(BigDecimal.valueOf(refundAmount).movePointLeft(2)); + + boolean save = refundRecordService.save(refundRecord); + ThrowUtils.throwIf(!save, ErrorCode.OPERATION_ERROR, "退款记录生成失败"); + } + + @@ -468,10 +569,21 @@ public class WeChatServiceImpl implements WeChatService { /** * 恢复商品库存 */ - private void recoverGoodInventory(String orderId) { - QueryWrapper orderItemsQueryWrapper = new QueryWrapper<>(); - orderItemsQueryWrapper.eq("orderId", orderId); - List orderItemsList = orderItemService.list(orderItemsQueryWrapper); + private void recoverGoodInventory(Order order) { + // 获取订单明细id列表 + QueryWrapper queryWrapper = new QueryWrapper<>(); + queryWrapper.eq("orderId", order.getId()); + List orderItemsList = orderItemService.list(queryWrapper); + + // 获取退款的订单明细id + QueryWrapper recordQueryWrapper = new QueryWrapper<>(); + recordQueryWrapper.eq("outTradeNo", order.getOrderNumber()); + List refundRecordList = refundRecordService.list(recordQueryWrapper); + List itemRefundIds = refundRecordList.stream().map(refundRecord -> + Long.parseLong(RefundUtils.parseRefundNoToItemId(refundRecord.getOutRefundNo()))).toList(); + + orderItemsList = orderItemsList.stream().filter(orderItems -> !itemRefundIds.contains(orderItems.getId())).toList(); + // 获取商品id列表 List goodIds = orderItemsList.stream().map(orderItems -> { GoodSnapshot goodSnapshot = orderItems.getGoodSnapshot();