liujc 1 год назад
Родитель
Сommit
0f014ed69a

+ 37 - 1
cooleshow-user/user-admin/src/main/java/com/yonge/cooleshow/admin/controller/open/UserPaymentClient.java

@@ -15,6 +15,8 @@ import com.yeepay.g3.sdk.yop.utils.DigitalEnvelopeUtils;
 import com.yeepay.g3.sdk.yop.utils.RSAKeyUtils;
 import com.yonge.cooleshow.biz.dal.entity.PaymentMerchantConfig;
 import com.yonge.cooleshow.biz.dal.entity.TenantMember;
+import com.yonge.cooleshow.biz.dal.entity.UserOrderRefund;
+import com.yonge.cooleshow.biz.dal.entity.UserOrderRefundBill;
 import com.yonge.cooleshow.biz.dal.enums.AuthStatusEnum;
 import com.yonge.cooleshow.biz.dal.service.*;
 import com.yonge.cooleshow.biz.dal.wrapper.UserPaymentOrderWrapper;
@@ -57,6 +59,8 @@ public class UserPaymentClient {
     @Autowired
     private PaymentMerchantConfigService paymentMerchantConfigService;
 
+    @Autowired
+    private UserOrderRefundBillService userOrderRefundBillService;
     /**
      * 支付消息回调
      * @param request HttpServletRequest
@@ -77,7 +81,7 @@ public class UserPaymentClient {
         log.info("payment vendor={}, paymentResp={}", vendor, JSON.toJSONString(paymentResp));
         // 支付订单确认
         UserPaymentOrderWrapper.UserPaymentOrder paymentOrder = userPaymentOrderService
-                .getUserPaymentOrderByOrderNo(paymentResp.getTransNo(), paymentResp.getMerOrderNo());
+                .getUserPaymentOrderByOrderNo( paymentResp.getMerOrderNo());
         if (Objects.isNull(paymentOrder)) {
             return paymentResp.getMsg();
         }
@@ -114,6 +118,38 @@ public class UserPaymentClient {
     }
 
 
+    /**
+     * 退款消息回调
+     * @param request HttpServletRequest
+     * @return String
+     */
+    @ApiOperation(value = "退款消息回调", notes = "三方支付平台退款消息通知")
+    @ApiImplicitParams({
+            @ApiImplicitParam(name = "vendor", value = "服务提供方", dataType = "String")
+    })
+    @RequestMapping(value = "/refund/callback/{vendor}", method = {RequestMethod.GET, RequestMethod.POST})
+    public String refund(@PathVariable("vendor") String vendor, HttpServletRequest request) {
+
+        RefundResp refundResp = paymentServiceContext.getPaymentService(vendor).callbackNotifyForRefund(request);
+        if (Objects.isNull(refundResp)) {
+            log.info("refund REFUND_FAILED, vendor={}", vendor);
+            return null;
+        }
+        log.info("refund vendor={}, refundResp={}", vendor, JSON.toJSONString(refundResp));
+
+        // 退款订单确认
+        UserOrderRefundBill refundBill = userOrderRefundBillService.getByTransNoOrOrderNo(refundResp.getTransNo(), refundResp.getMerOrderNo());
+        if (Objects.isNull(refundBill)) {
+            log.warn("refund REFUND_FAILED, vendor={}, refundResp={}", vendor, JSON.toJSONString(refundResp));
+            return refundResp.getMsg();
+        }
+
+        // 执行退款回调流程
+        userPaymentCoreService.refundPaymentCallback(refundResp);
+
+        return paymentServiceContext.getPaymentService(vendor).returnNotifyResult(request);
+    }
+
     @PostMapping("/callback/adapay")
     public String callback(HttpServletRequest request) {
         try {

+ 2 - 1
cooleshow-user/user-biz/src/main/java/com/yonge/cooleshow/biz/dal/dao/UserOrderRefundBillDao.java

@@ -26,5 +26,6 @@ public interface UserOrderRefundBillDao extends BaseMapper<UserOrderRefundBill>{
      * @return: com.yonge.cooleshow.biz.dal.vo.UserOrderRefundPaymentVo
 	 */
 	List<UserOrderRefundBillVo> selectPage(@Param("page") IPage page, @Param("param") UserOrderRefundPaymentSearch userOrderRefundPayment);
-	
+
+    UserOrderRefundBill getByTransNoOrOrderNo(@Param("transNo") String transNo, @Param("refundOrderNo") String refundOrderNo);
 }

+ 2 - 0
cooleshow-user/user-biz/src/main/java/com/yonge/cooleshow/biz/dal/service/UserOrderRefundBillService.java

@@ -26,4 +26,6 @@ public interface UserOrderRefundBillService extends IService<UserOrderRefundBill
  	 * @date 2022-05-09
      */
     IPage<UserOrderRefundBillVo> selectPage(IPage<UserOrderRefundBillVo> page, UserOrderRefundPaymentSearch query);
+
+    UserOrderRefundBill getByTransNoOrOrderNo(String transNo, String refundOrderNo);
 }

+ 9 - 0
cooleshow-user/user-biz/src/main/java/com/yonge/cooleshow/biz/dal/service/UserPaymentCoreService.java

@@ -2,6 +2,7 @@ package com.yonge.cooleshow.biz.dal.service;
 
 import com.microsvc.toolkit.config.jwt.utils.JwtUserInfo;
 import com.microsvc.toolkit.middleware.payment.common.api.entity.PaymentResp;
+import com.microsvc.toolkit.middleware.payment.common.api.entity.RefundResp;
 import com.yonge.cooleshow.biz.dal.wrapper.UserPaymentOrderWrapper;
 import com.yonge.cooleshow.common.enums.payment.EPaymentType;
 import org.springframework.transaction.annotation.Transactional;
@@ -76,4 +77,12 @@ public interface UserPaymentCoreService {
      * @param payTypeReq UserPaymentOrderWrapper.OrderPayTypeReq
      */
     UserPaymentOrderWrapper.OrderPayTypeResp orderPayType(UserPaymentOrderWrapper.OrderPayTypeReq payTypeReq);
+
+    /**
+     * 退款回调
+     *
+     */
+    void refundPaymentCallback(RefundResp refundResp);
+
+    void refundPayment(String orderNo,  String reason);
 }

+ 1 - 1
cooleshow-user/user-biz/src/main/java/com/yonge/cooleshow/biz/dal/service/UserPaymentOrderService.java

@@ -28,7 +28,7 @@ public interface UserPaymentOrderService   {
      * @param merOrderNo 订单编号
      * @return UserPaymentOrder
      */
-    UserPaymentOrderWrapper.UserPaymentOrder getUserPaymentOrderByOrderNo(String transNo, String merOrderNo);
+    UserPaymentOrderWrapper.UserPaymentOrder getUserPaymentOrderByOrderNo( String merOrderNo);
 
     /**
      * 用户支付订单

+ 14 - 4
cooleshow-user/user-biz/src/main/java/com/yonge/cooleshow/biz/dal/service/impl/CourseGroupServiceImpl.java

@@ -5,6 +5,7 @@ import com.baomidou.mybatisplus.core.metadata.IPage;
 import com.baomidou.mybatisplus.core.toolkit.Wrappers;
 import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
 import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import com.microsvc.toolkit.config.jwt.utils.JwtUserInfo;
 import com.yonge.cooleshow.auth.api.client.SysUserFeignService;
 import com.yonge.cooleshow.auth.api.entity.SysUser;
 import com.yonge.cooleshow.biz.dal.constant.CourseConstant;
@@ -26,6 +27,7 @@ import com.yonge.cooleshow.biz.dal.wrapper.UserPaymentOrderWrapper;
 import com.yonge.cooleshow.biz.dal.wrapper.coupon.CouponOrderWrapper;
 import com.yonge.cooleshow.common.constant.SysConfigConstant;
 import com.yonge.cooleshow.common.entity.HttpResponseResult;
+import com.yonge.cooleshow.common.enums.EPaymentVersion;
 import com.yonge.cooleshow.common.enums.PostStatusEnum;
 import com.yonge.cooleshow.common.enums.YesOrNoEnum;
 import com.yonge.toolset.base.exception.BizException;
@@ -110,6 +112,9 @@ public class CourseGroupServiceImpl extends ServiceImpl<CourseGroupDao, CourseGr
     @Autowired
     private PlatformCashAccountRecordService platformCashAccountRecordService;
 
+    @Autowired
+    private UserPaymentCoreService userPaymentCoreService;
+
     @Override
     public CourseGroupDao getDao() {
         return this.baseMapper;
@@ -1296,14 +1301,19 @@ public class CourseGroupServiceImpl extends ServiceImpl<CourseGroupDao, CourseGr
     private void refund(CourseGroup courseGroup) {
         // 退款
         List<String> orderNoList = courseScheduleStudentPaymentService.getOrderNoByGroupId(courseGroup.getId());
-        for (String orderNo : orderNoList) {
+        Collection<UserOrder> userOrders = userOrderService.listByIds(orderNoList);
+        for (UserOrder order : userOrders) {
             try {
-                userOrderRefundService.orderRefund(orderNo, "直播课成课失败退款");
+                if (order.getPaymentVersion().equals(EPaymentVersion.V1)) {
+                    userOrderRefundService.orderRefund(order.getOrderNo(), "直播课成课失败退款");
+                } else {
+                    userPaymentCoreService.refundPayment(order.getOrderNo(),"直播课成课失败退款");
+                }
 
                 //退还优惠券
-                couponInfoService.updateUserOrderCouponInfo(CouponOrderWrapper.builder().orderNo(orderNo).reset(true).build());
+                couponInfoService.updateUserOrderCouponInfo(CouponOrderWrapper.builder().orderNo(order.getOrderNo()).reset(true).build());
             } catch (Exception e) {
-                log.warn("直播课成课失败退款 退款失败,退款订单号 {}", orderNo);
+                log.warn("直播课成课失败退款 退款失败,退款订单号 {}", order);
                 log.error("直播课成课失败退款 退款失败", e.getCause());
             }
         }

+ 7 - 1
cooleshow-user/user-biz/src/main/java/com/yonge/cooleshow/biz/dal/service/impl/UserOrderRefundBillServiceImpl.java

@@ -25,5 +25,11 @@ public class UserOrderRefundBillServiceImpl extends ServiceImpl<UserOrderRefundB
     public IPage<UserOrderRefundBillVo> selectPage(IPage<UserOrderRefundBillVo> page, UserOrderRefundPaymentSearch query){
         return page.setRecords(baseMapper.selectPage(page, query));
     }
-	
+
+    @Override
+    public UserOrderRefundBill getByTransNoOrOrderNo(String transNo, String refundOrderNo) {
+
+        return baseMapper.getByTransNoOrOrderNo(transNo, refundOrderNo);
+    }
+
 }

+ 120 - 9
cooleshow-user/user-biz/src/main/java/com/yonge/cooleshow/biz/dal/service/impl/UserPaymentCoreServiceImpl.java

@@ -12,16 +12,10 @@ import com.microsvc.toolkit.common.webportal.exception.BizException;
 import com.microsvc.toolkit.config.jwt.utils.JwtUserInfo;
 import com.microsvc.toolkit.middleware.payment.common.api.BasePaymentService;
 import com.microsvc.toolkit.middleware.payment.common.api.PaymentServiceContext;
-import com.microsvc.toolkit.middleware.payment.common.api.entity.PaymentClose;
-import com.microsvc.toolkit.middleware.payment.common.api.entity.PaymentOrder;
-import com.microsvc.toolkit.middleware.payment.common.api.entity.PaymentReq;
-import com.microsvc.toolkit.middleware.payment.common.api.entity.PaymentResp;
+import com.microsvc.toolkit.middleware.payment.common.api.entity.*;
 import com.microsvc.toolkit.middleware.payment.common.api.enums.PaymentStatus;
 import com.yonge.cooleshow.biz.dal.entity.*;
-import com.yonge.cooleshow.biz.dal.enums.ClientEnum;
-import com.yonge.cooleshow.biz.dal.enums.GoodTypeEnum;
-import com.yonge.cooleshow.biz.dal.enums.OrderStatusEnum;
-import com.yonge.cooleshow.biz.dal.enums.SourceTypeEnum;
+import com.yonge.cooleshow.biz.dal.enums.*;
 import com.yonge.cooleshow.biz.dal.enums.coupon.CouponCategoryEnum;
 import com.yonge.cooleshow.biz.dal.service.*;
 import com.yonge.cooleshow.biz.dal.vo.UserOrderDetailVo;
@@ -32,6 +26,7 @@ import com.yonge.cooleshow.common.enums.*;
 import com.yonge.cooleshow.common.enums.payment.EPaymentChannel;
 import com.yonge.cooleshow.common.enums.payment.EPaymentStatus;
 import com.yonge.cooleshow.common.enums.payment.EPaymentType;
+import com.yonge.toolset.payment.base.enums.TradeStatusEnum;
 import com.yonge.toolset.payment.util.DistributedLock;
 import lombok.extern.slf4j.Slf4j;
 import org.apache.commons.collections.CollectionUtils;
@@ -124,6 +119,14 @@ public class UserPaymentCoreServiceImpl implements UserPaymentCoreService {
     @Autowired
     private PaymentMerchantConfigService paymentMerchantConfigService;
 
+    @Autowired
+    private UserOrderRefundService userOrderRefundService;
+
+    @Autowired
+    private UserOrderRefundBillService userOrderRefundBillService;
+
+
+
 
     // 订单商品参数校验,获取订单支付金额
     private static final Map<GoodTypeEnum, Consumer<UserPaymentOrderWrapper.OrderGoodsInfo>> orderGoodsCreate = Maps.newHashMap();
@@ -209,7 +212,7 @@ public class UserPaymentCoreServiceImpl implements UserPaymentCoreService {
         DistributedLock.of(redissonClient).runIfLockCanGet(lockName, () -> {
 
             // 获取订单信息
-            UserPaymentOrderWrapper.UserPaymentOrder paymentOrder = userPaymentOrderService.getUserPaymentOrderByOrderNo(paymentResp.getTransNo(), paymentResp.getMerOrderNo());
+            UserPaymentOrderWrapper.UserPaymentOrder paymentOrder = userPaymentOrderService.getUserPaymentOrderByOrderNo( paymentResp.getMerOrderNo());
             if (Objects.isNull(paymentOrder)) {
                 log.error("executePaymentCallback 无效的支付订单, paymentResp={}", JSON.toJSONString(paymentResp));
                 throw new BizException("无效的支付订单");
@@ -1017,6 +1020,48 @@ public class UserPaymentCoreServiceImpl implements UserPaymentCoreService {
     }
 
     /**
+     * 退款回调
+     *
+     */
+    @Override
+    @Transactional(rollbackFor = Exception.class)
+    public void refundPaymentCallback(RefundResp refundResp) {
+
+        String lockName = redisCacheService.getPaymentCacheKey(refundResp.getMerOrderNo());
+        // 并发执行锁
+        DistributedLock.of(redissonClient).runIfLockCanGet(lockName, () -> {
+            // 退款订单确认
+            UserOrderRefundBill refundOrder = userOrderRefundBillService.getByTransNoOrOrderNo(refundResp.getTransNo(), refundResp.getMerOrderNo());
+            if (Objects.isNull(refundOrder)) {
+                throw new com.yonge.toolset.base.exception.BizException("退款订单不存在");
+            }
+
+            refundOrder.setUpdateTime(new Date());
+            refundOrder.setTransNo(refundResp.getTransNo());
+            // 退款申请失败
+            if (PaymentStatus.FAILED == refundResp.getPaymentStatus()) {
+
+                // 更新用户退款订单状态
+                refundOrder.setStatus(TradeStatusEnum.failed);
+                refundOrder.setPayFailMsg(refundResp.getMsg());
+            }
+
+            // 退款处理已完成,本地订单状态未同步
+            if (PaymentStatus.SUCCESSED == refundResp.getPaymentStatus()) {
+
+                refundOrder.setBackRefundAmt(refundResp.getRefundAmount());
+                refundOrder.setStatus(TradeStatusEnum.succeeded);
+            }
+            userOrderRefundBillService.updateById(refundOrder);
+
+
+        }, 60L, TimeUnit.SECONDS);
+
+
+        log.info("refundPaymentCallback refundResp={}", JSON.toJSONString(refundResp));
+    }
+
+    /**
      * 定时更新订单状态
      * @param page IPage<UserPaymentOrderWrapper.UserPaymentOrder>
      * @param orderQuery UserPaymentOrderWrapper.UserPaymentOrderQuery
@@ -1101,4 +1146,70 @@ public class UserPaymentCoreServiceImpl implements UserPaymentCoreService {
         //log.info("scheduleUpdatePaymentOrderStatus PAYMENT_FINISH ------> ");
     }
 
+
+    /**
+     * 用户申请退款
+     *
+     */
+    @Transactional(rollbackFor = Exception.class)
+    @Override
+    public void refundPayment(String orderNo, String reason) {
+
+        // 查询订单信息,支付状态
+        UserPaymentOrderWrapper.UserPaymentOrder paymentOrder = userPaymentOrderService.getUserPaymentOrderByOrderNo(orderNo);
+        if (Objects.isNull(paymentOrder)) {
+            throw new BizException("订单信息不存在");
+        }
+        if (!OrderStatusEnum.PAID.getCode().equals(paymentOrder.getStatus().getCode())) {
+            throw  new BizException("订单状态异常");
+        }
+
+
+        // 执行状态锁定
+        String lockName = redisCacheService.getExecuteOrderCacheKey(paymentOrder.getUserId().toString());
+        DistributedLock.of(redissonClient).runIfLockCanGet(lockName, () -> {
+            // 提交退款申请记录
+            UserOrderRefund userRefundOrder = new UserOrderRefund();
+            userRefundOrder.setUserId(paymentOrder.getId());
+            userRefundOrder.setOrderId(paymentOrder.getId());
+            userRefundOrder.setOrderNo(paymentOrder.getOrderNo());
+            userRefundOrder.setOredrDetilIds(paymentOrder.getTransNo());
+            userRefundOrder.setStatus(AuthStatusEnum.PASS);
+            userRefundOrder.setApplyAmount(paymentOrder.getPaymentCashAmount());
+            userRefundOrder.setActualAmount(paymentOrder.getPaymentCouponAmount());
+            userRefundOrder.setReason(reason);
+            userOrderRefundService.save(userRefundOrder);
+
+            //入退款单表
+            UserOrderRefundBill orderRefundBill = new UserOrderRefundBill();
+            orderRefundBill.setRefundId(userRefundOrder.getId());
+            orderRefundBill.setBillNo(IdWorker.getIdStr());
+            orderRefundBill.setRefundAmt(userRefundOrder.getActualAmount());
+
+
+            RefundOrder refundOrder = new RefundOrder();
+            refundOrder.setUserId(paymentOrder.getUserId().toString());
+            refundOrder.setMerOrderNo(orderRefundBill.getBillNo());
+            refundOrder.setRefundAmount(orderRefundBill.getRefundAmt());
+            refundOrder.setOrderAmount(paymentOrder.getPaymentCashAmount());
+            refundOrder.setReason(reason);
+            refundOrder.setPaymentOrderNo(paymentOrder.getOrderNo());
+            RefundResp refundResp = paymentServiceContext.getPaymentService(paymentOrder.getPaymentVendor()).refund(refundOrder);
+            // 申请请求失败
+            if (PaymentStatus.FAILED == refundResp.getPaymentStatus()) {
+                orderRefundBill.setStatus(TradeStatusEnum.failed);
+                orderRefundBill.setPayFailMsg(refundResp.getMsg());
+            } else {
+                orderRefundBill.setTransNo(refundResp.getTransNo());
+                orderRefundBill.setStatus(TradeStatusEnum.pending);
+            }
+            userOrderRefundBillService.save(orderRefundBill);
+
+            //处理退款业务
+           userOrderRefundService.orderRefundSuccessBizHandle(userRefundOrder.getId());
+
+        }, 10L, TimeUnit.SECONDS);
+
+    }
+
 }

+ 2 - 3
cooleshow-user/user-biz/src/main/java/com/yonge/cooleshow/biz/dal/service/impl/UserPaymentOrderServiceImpl.java

@@ -46,12 +46,11 @@ public class UserPaymentOrderServiceImpl  implements UserPaymentOrderService {
     /**
      * 用户支付订单信息
      *
-     * @param transNo 交易流水号
      * @param merOrderNo 订单编号
      * @return UserPaymentOrder
      */
     @Override
-    public UserPaymentOrderWrapper.UserPaymentOrder getUserPaymentOrderByOrderNo(String transNo, String merOrderNo) {
+    public UserPaymentOrderWrapper.UserPaymentOrder getUserPaymentOrderByOrderNo(String merOrderNo) {
 
         // 查询订单信息
         UserOrder one = userOrderService.lambdaQuery()
@@ -68,7 +67,7 @@ public class UserPaymentOrderServiceImpl  implements UserPaymentOrderService {
         }
 
         // 查询订单支付信息
-        UserOrderPayment newestPayment = userOrderPaymentService.getNewestPayment(transNo, merOrderNo);
+        UserOrderPayment newestPayment = userOrderPaymentService.getNewestPayment(null, merOrderNo);
 
         return UserPaymentOrderWrapper.UserPaymentOrder.from(one, newestPayment);
 

+ 13 - 0
cooleshow-user/user-biz/src/main/resources/config/mybatis/UserOrderRefundBillMapper.xml

@@ -42,4 +42,17 @@
         <include refid="baseColumns" />
         FROM user_order_refund_payment t
     </select>
+
+    <select id="getByTransNoOrOrderNo" resultMap="BaseResultMap">
+        select t.*
+        from user_order_refund_bill t
+        <where>
+            <if test="refundOrderNo != null and refundOrderNo != ''">
+                and t.bill_no_ = #{refundOrderNo}
+            </if>
+            <if test="transNo != null and transNo != ''">
+                and t.trans_no_ = #{transNo}
+            </if>
+        </where>
+    </select>
 </mapper>