diff --git a/bnyer-common/bnyer-common-core/src/main/java/com/bnyer/common/core/domain/R.java b/bnyer-common/bnyer-common-core/src/main/java/com/bnyer/common/core/domain/R.java index 035eb42..29ea906 100644 --- a/bnyer-common/bnyer-common-core/src/main/java/com/bnyer/common/core/domain/R.java +++ b/bnyer-common/bnyer-common-core/src/main/java/com/bnyer/common/core/domain/R.java @@ -83,7 +83,7 @@ public class R implements Serializable * @return */ public R buildRepeatRequest(int time){ - return restResult(null,ResponseEnum.REPEAT_REQUEST_ERROR.getCode(),time+"分钟内"+ResponseEnum.REPEAT_REQUEST_ERROR.getMsg()); + return restResult(null,ResponseEnum.REPEAT_REQUEST_ERROR.getCode(),time+"秒内"+ResponseEnum.REPEAT_REQUEST_ERROR.getMsg()); } private static R restResult(T data, int code, String msg) diff --git a/bnyer-common/bnyer-common-core/src/main/java/com/bnyer/common/core/enums/EnumRefundStatus.java b/bnyer-common/bnyer-common-core/src/main/java/com/bnyer/common/core/enums/EnumRefundStatus.java new file mode 100644 index 0000000..9a3351a --- /dev/null +++ b/bnyer-common/bnyer-common-core/src/main/java/com/bnyer/common/core/enums/EnumRefundStatus.java @@ -0,0 +1,32 @@ +package com.bnyer.common.core.enums; + +import lombok.AllArgsConstructor; +import lombok.Getter; + +import java.util.Arrays; + +/** + * @author :WXC + * @description : + */ +@Getter +@AllArgsConstructor +public enum EnumRefundStatus { + + NO_REFUND(1000,"未退款"), + FAILS(1001,"退款失败"), + SUCCESS(1002,"退款成功"), + PROCESS(1003,"退款中"), + ; + + private final int status; + + private final String name; + + public static EnumRefundStatus getEnumStatusByStatus(int status) { + return Arrays.stream(values()) + .filter(payStatus -> payStatus.getStatus() == status) + .findFirst().orElseThrow(() -> new SecurityException("status 未匹配上对应的支付状态")); + } + +} diff --git a/bnyer-common/bnyer-common-core/src/main/java/com/bnyer/common/core/enums/ResponseEnum.java b/bnyer-common/bnyer-common-core/src/main/java/com/bnyer/common/core/enums/ResponseEnum.java index e84e13a..5e6633d 100644 --- a/bnyer-common/bnyer-common-core/src/main/java/com/bnyer/common/core/enums/ResponseEnum.java +++ b/bnyer-common/bnyer-common-core/src/main/java/com/bnyer/common/core/enums/ResponseEnum.java @@ -10,7 +10,7 @@ public enum ResponseEnum { //======================系统异常========================, SERVER_ERROR(500, "系统繁忙,请稍候重试!"), NOT_AUTH(500, "未登录!"), - REPEAT_REQUEST_ERROR(500, "请勿重复请求"), + REPEAT_REQUEST_ERROR(500, "请勿重复提交"), PARAM_ERROR(400, "参数异常!"), @@ -30,6 +30,7 @@ public enum ResponseEnum { //======================第三方接口调用异常======================== PAY_FAILS(220001,"支付失败,请稍后重试"), ORDER_QUERY_FAILS(220002,"订单查询失败,请稍后重试"), + REFUND_FAILS(220003,"退款失败,请稍后重试"), ; diff --git a/bnyer-services/bnyer-img/src/main/java/com/bnyer/img/query/UserVipRecordQuery.java b/bnyer-services/bnyer-img/src/main/java/com/bnyer/img/query/UserVipRecordQuery.java index 3f2c6a6..14b89f1 100644 --- a/bnyer-services/bnyer-img/src/main/java/com/bnyer/img/query/UserVipRecordQuery.java +++ b/bnyer-services/bnyer-img/src/main/java/com/bnyer/img/query/UserVipRecordQuery.java @@ -17,7 +17,9 @@ public class UserVipRecordQuery { @ApiModelProperty(value = "id") private Long id; - @ApiModelProperty(value = "用户id") + /** + * 用户id + */ private Long userId; /** * 用户客户端类型 diff --git a/bnyer-services/bnyer-order/src/main/java/com/bnyer/order/annotation/LimitRepeatRequest.java b/bnyer-services/bnyer-order/src/main/java/com/bnyer/order/annotation/LimitRepeatRequest.java index c27d369..a300398 100644 --- a/bnyer-services/bnyer-order/src/main/java/com/bnyer/order/annotation/LimitRepeatRequest.java +++ b/bnyer-services/bnyer-order/src/main/java/com/bnyer/order/annotation/LimitRepeatRequest.java @@ -31,7 +31,7 @@ public @interface LimitRepeatRequest { * 当前时间内 api 只能请求一次,单位秒 * @return */ - int time() default 5; + long time() default 5; /** * 对部分参数做重复请求限制 diff --git a/bnyer-services/bnyer-order/src/main/java/com/bnyer/order/aop/LimitRepeatRequestAspect.java b/bnyer-services/bnyer-order/src/main/java/com/bnyer/order/aop/LimitRepeatRequestAspect.java index b13f80b..12973e0 100644 --- a/bnyer-services/bnyer-order/src/main/java/com/bnyer/order/aop/LimitRepeatRequestAspect.java +++ b/bnyer-services/bnyer-order/src/main/java/com/bnyer/order/aop/LimitRepeatRequestAspect.java @@ -1,14 +1,15 @@ -package com.bnyer.order.aop; +package com.bnyer.pay.aop; import cn.hutool.core.collection.CollUtil; import com.alibaba.fastjson.JSON; import com.alibaba.fastjson.JSONArray; import com.alibaba.fastjson.JSONObject; -import com.bnyer.common.core.domain.R; +import com.bnyer.common.core.enums.ResponseEnum; +import com.bnyer.common.core.exception.ServiceException; import com.bnyer.common.core.utils.MD5Util; import com.bnyer.common.core.utils.StringUtils; import com.bnyer.common.core.vo.UserInfoVo; -import com.bnyer.common.redis.service.RedisService; +import com.bnyer.common.redis.service.RedissonService; import com.bnyer.common.security.utils.SecurityUtils; import com.bnyer.order.annotation.LimitRepeatRequest; import lombok.extern.slf4j.Slf4j; @@ -17,9 +18,10 @@ import org.aspectj.lang.Signature; import org.aspectj.lang.annotation.Around; import org.aspectj.lang.annotation.Aspect; import org.aspectj.lang.reflect.MethodSignature; -import org.springframework.beans.factory.annotation.Autowired; +import org.redisson.api.RLock; import org.springframework.stereotype.Component; +import javax.annotation.Resource; import java.lang.reflect.Method; import java.util.Objects; import java.util.concurrent.TimeUnit; @@ -34,25 +36,24 @@ import java.util.concurrent.TimeUnit; @Component public class LimitRepeatRequestAspect { - @Autowired - private RedisService redisService; + @Resource + private RedissonService redissonService; @Around("@annotation(limitRepeatRequest)") public Object around(ProceedingJoinPoint joinPoint, LimitRepeatRequest limitRepeatRequest) throws Throwable{ String key = getKey(joinPoint,limitRepeatRequest); - Object cacheObject = redisService.getCacheObject(key); - Object message; - if (Objects.nonNull(cacheObject)){ + RLock rLock = redissonService.getRLock(key); + boolean flag = rLock.tryLock(0,limitRepeatRequest.time(), TimeUnit.SECONDS); + if (!flag){ if (StringUtils.isNotBlank(limitRepeatRequest.message())){ - message = limitRepeatRequest.message(); + throw new ServiceException(limitRepeatRequest.message(),ResponseEnum.REPEAT_REQUEST_ERROR.getCode()); }else { - message = new R().buildRepeatRequest(limitRepeatRequest.time()); + throw new ServiceException(limitRepeatRequest.time()+"秒内"+ResponseEnum.REPEAT_REQUEST_ERROR.getMsg(), + ResponseEnum.REPEAT_REQUEST_ERROR.getCode()); } - }else { - redisService.setCacheObject(key,"1",(long)limitRepeatRequest.time(), TimeUnit.SECONDS); - message = joinPoint.proceed(); } - return message; + Object proceed = joinPoint.proceed(); + return proceed; } /** @@ -63,13 +64,13 @@ public class LimitRepeatRequestAspect { * @return */ private String getKey(ProceedingJoinPoint joinPoint, LimitRepeatRequest limitRepeatRequest) { - UserInfoVo userInfo = SecurityUtils.getUserInfo(); Method currentMethod = getCurrentMethod(joinPoint); //最后拼接好的key StringBuilder key = new StringBuilder("LimitRepeatRequestAspect#" + currentMethod.getName()); //限制范围 String userRange = limitRepeatRequest.userRange(); if (LimitRepeatRequest.SELF.equals(userRange)){ + UserInfoVo userInfo = SecurityUtils.getUserInfo(); key.append("#"); key.append(userInfo.getUserClientType()); key.append("#"); @@ -97,7 +98,7 @@ public class LimitRepeatRequestAspect { String value = requestParams.containsKey(param)?requestParams.getString(param):""; key.append(value); }else if(obj instanceof Integer){ - String value = requestParams.containsKey(param)?requestParams.getString(param):""; + String value = requestParams.containsKey(param)?String.valueOf(requestParams.getInteger(param)):""; key.append(value); } } @@ -120,9 +121,7 @@ public class LimitRepeatRequestAspect { private JSONObject getRequestParams(ProceedingJoinPoint joinPoint) { Object[] args = joinPoint.getArgs(); if (args != null && args.length != 0){ - String jsonString = JSON.toJSONString(args); - JSONArray parseArray = JSON.parseArray(jsonString); - return parseArray.getJSONObject(0); + return JSON.parseObject(args[0].toString()); } return null; } diff --git a/bnyer-services/bnyer-order/src/main/java/com/bnyer/order/service/impl/VipOrderServiceImpl.java b/bnyer-services/bnyer-order/src/main/java/com/bnyer/order/service/impl/VipOrderServiceImpl.java index faea940..05c08cf 100644 --- a/bnyer-services/bnyer-order/src/main/java/com/bnyer/order/service/impl/VipOrderServiceImpl.java +++ b/bnyer-services/bnyer-order/src/main/java/com/bnyer/order/service/impl/VipOrderServiceImpl.java @@ -124,7 +124,7 @@ public class VipOrderServiceImpl extends ServiceImpl i //查询会员信息 R userVipResult = remoteUserVipService.queryUserVip(addVipOrderDto.getVipId()); if (!userVipResult.isSuccess()){ - log.error("内部接口调用异常:url:{}request{},result{},error:{}","queryUserVipList", addVipOrderDto.getVipId(),JSON.toJSONString(userVipResult),userVipResult.getMsg()); + log.error("内部接口调用异常:url:{}request{},result{},error:{}","queryUserVip", addVipOrderDto.getVipId(),JSON.toJSONString(userVipResult),userVipResult.getMsg()); throw new ServiceException(userVipResult.getMsg()); } UserVipVo userVipVo = userVipResult.getData(); diff --git a/bnyer-services/bnyer-pay/src/main/java/com/bnyer/pay/annotation/LimitRepeatRequest.java b/bnyer-services/bnyer-pay/src/main/java/com/bnyer/pay/annotation/LimitRepeatRequest.java index 605b466..c226583 100644 --- a/bnyer-services/bnyer-pay/src/main/java/com/bnyer/pay/annotation/LimitRepeatRequest.java +++ b/bnyer-services/bnyer-pay/src/main/java/com/bnyer/pay/annotation/LimitRepeatRequest.java @@ -31,7 +31,7 @@ public @interface LimitRepeatRequest { * 当前时间内 api 只能请求一次,单位秒 * @return */ - int time() default 5; + long time() default 5; /** * 对部分参数做重复请求限制 diff --git a/bnyer-services/bnyer-pay/src/main/java/com/bnyer/pay/aop/LimitRepeatRequestAspect.java b/bnyer-services/bnyer-pay/src/main/java/com/bnyer/pay/aop/LimitRepeatRequestAspect.java index e3116f0..fa81d3b 100644 --- a/bnyer-services/bnyer-pay/src/main/java/com/bnyer/pay/aop/LimitRepeatRequestAspect.java +++ b/bnyer-services/bnyer-pay/src/main/java/com/bnyer/pay/aop/LimitRepeatRequestAspect.java @@ -4,11 +4,12 @@ import cn.hutool.core.collection.CollUtil; import com.alibaba.fastjson.JSON; import com.alibaba.fastjson.JSONArray; import com.alibaba.fastjson.JSONObject; -import com.bnyer.common.core.domain.R; +import com.bnyer.common.core.enums.ResponseEnum; +import com.bnyer.common.core.exception.ServiceException; import com.bnyer.common.core.utils.MD5Util; import com.bnyer.common.core.utils.StringUtils; import com.bnyer.common.core.vo.UserInfoVo; -import com.bnyer.common.redis.service.RedisService; +import com.bnyer.common.redis.service.RedissonService; import com.bnyer.common.security.utils.SecurityUtils; import com.bnyer.pay.annotation.LimitRepeatRequest; import lombok.extern.slf4j.Slf4j; @@ -17,9 +18,10 @@ import org.aspectj.lang.Signature; import org.aspectj.lang.annotation.Around; import org.aspectj.lang.annotation.Aspect; import org.aspectj.lang.reflect.MethodSignature; -import org.springframework.beans.factory.annotation.Autowired; +import org.redisson.api.RLock; import org.springframework.stereotype.Component; +import javax.annotation.Resource; import java.lang.reflect.Method; import java.util.Objects; import java.util.concurrent.TimeUnit; @@ -34,25 +36,24 @@ import java.util.concurrent.TimeUnit; @Component public class LimitRepeatRequestAspect { - @Autowired - private RedisService redisService; + @Resource + private RedissonService redissonService; @Around("@annotation(limitRepeatRequest)") public Object around(ProceedingJoinPoint joinPoint, LimitRepeatRequest limitRepeatRequest) throws Throwable{ String key = getKey(joinPoint,limitRepeatRequest); - Object cacheObject = redisService.getCacheObject(key); - Object message; - if (Objects.nonNull(cacheObject)){ + RLock rLock = redissonService.getRLock(key); + boolean flag = rLock.tryLock(0,limitRepeatRequest.time(), TimeUnit.SECONDS); + if (!flag){ if (StringUtils.isNotBlank(limitRepeatRequest.message())){ - message = limitRepeatRequest.message(); + throw new ServiceException(limitRepeatRequest.message(),ResponseEnum.REPEAT_REQUEST_ERROR.getCode()); }else { - message = new R().buildRepeatRequest(limitRepeatRequest.time()); + throw new ServiceException(limitRepeatRequest.time()+"秒内"+ResponseEnum.REPEAT_REQUEST_ERROR.getMsg(), + ResponseEnum.REPEAT_REQUEST_ERROR.getCode()); } - }else { - redisService.setCacheObject(key,"1",(long)limitRepeatRequest.time(), TimeUnit.SECONDS); - message = joinPoint.proceed(); } - return message; + Object proceed = joinPoint.proceed(); + return proceed; } /** @@ -63,13 +64,13 @@ public class LimitRepeatRequestAspect { * @return */ private String getKey(ProceedingJoinPoint joinPoint, LimitRepeatRequest limitRepeatRequest) { - UserInfoVo userInfo = SecurityUtils.getUserInfo(); Method currentMethod = getCurrentMethod(joinPoint); //最后拼接好的key StringBuilder key = new StringBuilder("LimitRepeatRequestAspect#" + currentMethod.getName()); //限制范围 String userRange = limitRepeatRequest.userRange(); if (LimitRepeatRequest.SELF.equals(userRange)){ + UserInfoVo userInfo = SecurityUtils.getUserInfo(); key.append("#"); key.append(userInfo.getUserClientType()); key.append("#"); @@ -97,7 +98,7 @@ public class LimitRepeatRequestAspect { String value = requestParams.containsKey(param)?requestParams.getString(param):""; key.append(value); }else if(obj instanceof Integer){ - String value = requestParams.containsKey(param)?requestParams.getString(param):""; + String value = requestParams.containsKey(param)?String.valueOf(requestParams.getInteger(param)):""; key.append(value); } } @@ -120,9 +121,7 @@ public class LimitRepeatRequestAspect { private JSONObject getRequestParams(ProceedingJoinPoint joinPoint) { Object[] args = joinPoint.getArgs(); if (args != null && args.length != 0){ - String jsonString = JSON.toJSONString(args); - JSONArray parseArray = JSON.parseArray(jsonString); - return parseArray.getJSONObject(0); + return JSON.parseObject(args[0].toString()); } return null; } diff --git a/bnyer-services/bnyer-pay/src/main/java/com/bnyer/pay/bean/bo/RefundBo.java b/bnyer-services/bnyer-pay/src/main/java/com/bnyer/pay/bean/bo/RefundBo.java index 4e93fe0..6c34646 100644 --- a/bnyer-services/bnyer-pay/src/main/java/com/bnyer/pay/bean/bo/RefundBo.java +++ b/bnyer-services/bnyer-pay/src/main/java/com/bnyer/pay/bean/bo/RefundBo.java @@ -14,4 +14,29 @@ import lombok.Setter; @NoArgsConstructor public class RefundBo { + /** + * 应用id + */ + private String appId; + + /** + * 支付单号 + */ + private String payId; + + /** + * 退款单号 + */ + private String refundNo; + + /** + * 退款金额 + */ + private String refundAmount; + + /** + * 退款原因 + */ + private String reason; + } diff --git a/bnyer-services/bnyer-pay/src/main/java/com/bnyer/pay/bean/vo/ThirdPayBaseVo.java b/bnyer-services/bnyer-pay/src/main/java/com/bnyer/pay/bean/vo/ThirdPayBaseVo.java new file mode 100644 index 0000000..37805b7 --- /dev/null +++ b/bnyer-services/bnyer-pay/src/main/java/com/bnyer/pay/bean/vo/ThirdPayBaseVo.java @@ -0,0 +1,27 @@ +package com.bnyer.pay.bean.vo; + +import io.swagger.annotations.ApiModelProperty; +import lombok.Getter; +import lombok.Setter; + +/** + * @author :WXC + * @Date :2023/05/15 + * @description : + */ +@Getter +@Setter +public class ThirdPayBaseVo { + + @ApiModelProperty(value="错误码") + private String thirdCode; + + @ApiModelProperty(value="错误信息") + private String thirdMsg; + + @ApiModelProperty(value="流水号") + private String thirdNo; + + @ApiModelProperty(value = "完成时间") + private String successTime; +} diff --git a/bnyer-services/bnyer-pay/src/main/java/com/bnyer/pay/bean/vo/ThirdRefundVo.java b/bnyer-services/bnyer-pay/src/main/java/com/bnyer/pay/bean/vo/ThirdRefundVo.java index 51825af..f86a238 100644 --- a/bnyer-services/bnyer-pay/src/main/java/com/bnyer/pay/bean/vo/ThirdRefundVo.java +++ b/bnyer-services/bnyer-pay/src/main/java/com/bnyer/pay/bean/vo/ThirdRefundVo.java @@ -1,10 +1,67 @@ package com.bnyer.pay.bean.vo; +import lombok.Data; +import lombok.Getter; +import lombok.Setter; + /** * @author :WXC * @Date :2023/05/08 - * @description : + * @description :第三方支付退款信息 */ -public class ThirdRefundVo { +@Getter +@Setter +public class ThirdRefundVo extends ThirdPayBaseVo{ + + /** + * 微信退款信息 + */ + private WxRefundVo wxRefundVo; + + /** + * 支付宝退款信息 + */ + private AliRefundVo aliRefundVo; + + /** + * 抖音退款信息 + */ + private DyRefundVo dyRefundVo; + + /** + * 快手退款信息 + */ + private KsRefundVo ksRefundVo; + + @Data + public static class WxRefundVo{ + /** + * 退款状态 + * SUCCESS:退款成功 + * CLOSED:退款关闭 + * PROCESSING:退款处理中 + * ABNORMAL:退款异常 + */ + private String status; + + /** + * 退款渠道 + * ORIGINAL—原路退款 + * BALANCE—退回到余额 + * OTHER_BALANCE—原账户异常退到其他余额账户 + * OTHER_BANKCARD—原银行卡异常退到其他银行卡 + * 示例值:ORIGINAdL + */ + private String channel; + } + + @Data + public static class AliRefundVo{} + + @Data + public static class DyRefundVo{} + + @Data + public static class KsRefundVo{} } diff --git a/bnyer-services/bnyer-pay/src/main/java/com/bnyer/pay/bean/vo/ThirdUnifiedOrderVo.java b/bnyer-services/bnyer-pay/src/main/java/com/bnyer/pay/bean/vo/ThirdUnifiedOrderVo.java index 61e60fc..ecf0ef8 100644 --- a/bnyer-services/bnyer-pay/src/main/java/com/bnyer/pay/bean/vo/ThirdUnifiedOrderVo.java +++ b/bnyer-services/bnyer-pay/src/main/java/com/bnyer/pay/bean/vo/ThirdUnifiedOrderVo.java @@ -11,23 +11,15 @@ import java.io.Serializable; * @Date :2023/04/03 * @description :统一第三方支付下单返回参数 */ -@Data +@Getter +@Setter @NoArgsConstructor -public class ThirdUnifiedOrderVo implements Serializable { +public class ThirdUnifiedOrderVo extends ThirdPayBaseVo implements Serializable { private static final long serialVersionUID = 1L; @ApiModelProperty(value = "应用id") private String appId; - @ApiModelProperty(value="调用第三方下单返回") - private String thirdCode; - - @ApiModelProperty(value="调用第三方下单返回") - private String thirdMsg; - - @ApiModelProperty(value="调用第三方下单返回") - private String thirdNo; - @ApiModelProperty(value = "内部系统支付单号/开发者测单号") private String outOrderNo; diff --git a/bnyer-services/bnyer-pay/src/main/java/com/bnyer/pay/bean/vo/UnifiedOrderVo.java b/bnyer-services/bnyer-pay/src/main/java/com/bnyer/pay/bean/vo/UnifiedOrderVo.java index dac9b91..3116785 100644 --- a/bnyer-services/bnyer-pay/src/main/java/com/bnyer/pay/bean/vo/UnifiedOrderVo.java +++ b/bnyer-services/bnyer-pay/src/main/java/com/bnyer/pay/bean/vo/UnifiedOrderVo.java @@ -38,7 +38,7 @@ public class UnifiedOrderVo { private String nonceStr; @ApiModelProperty(value = "会话标识") private String packageValue; - @ApiModelProperty(value = "微信返回的字段") + @ApiModelProperty(value = "签名类型") private String signType; @ApiModelProperty(value = "签名") private String paySign; diff --git a/bnyer-services/bnyer-pay/src/main/java/com/bnyer/pay/design/strategy/DYPayStrategy.java b/bnyer-services/bnyer-pay/src/main/java/com/bnyer/pay/design/strategy/DYPayStrategy.java index 66914d1..7139e3d 100644 --- a/bnyer-services/bnyer-pay/src/main/java/com/bnyer/pay/design/strategy/DYPayStrategy.java +++ b/bnyer-services/bnyer-pay/src/main/java/com/bnyer/pay/design/strategy/DYPayStrategy.java @@ -161,7 +161,7 @@ public class DYPayStrategy extends AbstractPayStrategy{ //保存预下单信息 ThirdUnifiedOrderVo.DyThirdInOrderVo dyThirdInOrderVo = new ThirdUnifiedOrderVo.DyThirdInOrderVo(); thirdUnifiedOrderVo.setOutOrderNo(bo.getPayId()); - //把order_no和order_info_token返回前端用于调起收银台 + //把order_id和order_token返回前端用于调起收银台 dyThirdInOrderVo.setOrderId(orderId); dyThirdInOrderVo.setOrderToken(orderToken); thirdUnifiedOrderVo.setDyThirdInOrderVo(dyThirdInOrderVo); @@ -188,7 +188,7 @@ public class DYPayStrategy extends AbstractPayStrategy{ //订单信息的json字符串 String message = object.getString("msg"); JSONObject msgJsonObj = JSON.parseObject(message); - log.info("快手支付:统一回调处理,params:{}",message); + log.info("抖音支付:统一回调处理,params:{}",message); if (StringUtils.isBlank(msgSignature)) { log.info("抖音支付回调参数丢失,payId:{}",object.getString("cp_orderno")); return super.buildNotifyCheckResultMsg(EnumPayType.DY_PAY,false,"trade fail"); diff --git a/bnyer-services/bnyer-pay/src/main/java/com/bnyer/pay/design/strategy/WxPayStrategy.java b/bnyer-services/bnyer-pay/src/main/java/com/bnyer/pay/design/strategy/WxPayStrategy.java index 71d0557..c3c74e6 100644 --- a/bnyer-services/bnyer-pay/src/main/java/com/bnyer/pay/design/strategy/WxPayStrategy.java +++ b/bnyer-services/bnyer-pay/src/main/java/com/bnyer/pay/design/strategy/WxPayStrategy.java @@ -1,6 +1,7 @@ package com.bnyer.pay.design.strategy; import cn.hutool.core.date.DatePattern; +import cn.hutool.core.date.DateTime; import cn.hutool.core.date.DateUtil; import com.alibaba.fastjson.JSON; import com.bnyer.common.core.domain.WxpayConfig; @@ -15,22 +16,24 @@ import com.bnyer.pay.bean.bo.RefundBo; import com.bnyer.pay.bean.bo.UnifiedOrderBo; import com.bnyer.pay.bean.dto.EditPayInfoNotifyDto; import com.bnyer.pay.bean.dto.PayNotifyCheckDto; +import com.bnyer.pay.bean.vo.ThirdQueryOrderVo; +import com.bnyer.pay.bean.vo.ThirdRefundVo; +import com.bnyer.pay.bean.vo.ThirdUnifiedOrderVo; import com.bnyer.pay.enums.EnumPayChannel; import com.bnyer.pay.enums.EnumTradeType; import com.bnyer.pay.enums.EnumWxPayStatus; import com.bnyer.pay.manager.WxPayManager; import com.bnyer.pay.service.PayInfoService; import com.bnyer.pay.utils.WXPayUtil; -import com.bnyer.pay.bean.vo.ThirdRefundVo; -import com.bnyer.pay.bean.vo.ThirdUnifiedOrderVo; -import com.bnyer.pay.bean.vo.ThirdQueryOrderVo; import com.github.binarywang.wxpay.bean.notify.WxPayNotifyResponse; import com.github.binarywang.wxpay.bean.notify.WxPayOrderNotifyV3Result; import com.github.binarywang.wxpay.bean.request.BaseWxPayRequest; import com.github.binarywang.wxpay.bean.request.WxPayOrderQueryRequest; +import com.github.binarywang.wxpay.bean.request.WxPayRefundV3Request; import com.github.binarywang.wxpay.bean.request.WxPayUnifiedOrderV3Request; import com.github.binarywang.wxpay.bean.result.BaseWxPayResult; import com.github.binarywang.wxpay.bean.result.WxPayOrderQueryResult; +import com.github.binarywang.wxpay.bean.result.WxPayRefundV3Result; import com.github.binarywang.wxpay.bean.result.WxPayUnifiedOrderV3Result; import com.github.binarywang.wxpay.bean.result.enums.TradeTypeEnum; import com.github.binarywang.wxpay.exception.WxPayException; @@ -39,7 +42,6 @@ import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; -import java.util.Date; import java.util.Map; /** @@ -127,8 +129,8 @@ public class WxPayStrategy extends AbstractPayStrategy { } catch (WxPayException e) { log.error("微信支付:统一下单接口调用失败,payId:{},error{}", bo.getPayId(), e.getMessage()); thirdUnifiedOrderVo.setAppId(wxPayConfig.getAppid()); - thirdUnifiedOrderVo.setThirdCode(e.getResultCode()); - thirdUnifiedOrderVo.setThirdMsg(e.getMessage()); + thirdUnifiedOrderVo.setThirdCode(e.getErrCode()); + thirdUnifiedOrderVo.setThirdMsg(e.getErrCodeDes()); return thirdUnifiedOrderVo; } } @@ -227,6 +229,46 @@ public class WxPayStrategy extends AbstractPayStrategy { @Override public ThirdRefundVo refund(RefundBo bo) { - return null; + WxpayConfig config = wxPayManager.getWxPayConfigByAppId(bo.getAppId()); + WxPayService wxPayService = wxPayManager.getWxPayService(config); + ThirdRefundVo thirdRefundVo = new ThirdRefundVo(); + try { + WxPayRefundV3Request wxPayRefundV3Request = new WxPayRefundV3Request(); + //退款金额 + WxPayRefundV3Request.Amount amount = new WxPayRefundV3Request.Amount(); + amount.setRefund(Integer.parseInt(bo.getRefundAmount())); + wxPayRefundV3Request.setAmount(amount); + //退款单号 + wxPayRefundV3Request.setOutRefundNo(bo.getRefundNo()); + //退款原因 + wxPayRefundV3Request.setReason(bo.getReason()); + //支付单号 + wxPayRefundV3Request.setOutTradeNo(bo.getPayId()); + WxPayRefundV3Result wxPayRefundV3Result = wxPayService.refundV3(wxPayRefundV3Request); + //第三方返回 + thirdRefundVo.setThirdCode("0"); + thirdRefundVo.setThirdMsg("ok"); + + ThirdRefundVo.WxRefundVo wxRefundVo = new ThirdRefundVo.WxRefundVo(); + wxRefundVo.setChannel(wxPayRefundV3Result.getChannel()); + wxRefundVo.setStatus(wxPayRefundV3Result.getStatus()); + thirdRefundVo.setThirdNo(wxPayRefundV3Result.getRefundId()); + DateTime successTime = DateUtil.parse(wxPayRefundV3Result.getSuccessTime(), DatePattern.UTC_WITH_XXX_OFFSET_PATTERN); + thirdRefundVo.setSuccessTime(DateUtil.formatDateTime(successTime)); + thirdRefundVo.setWxRefundVo(wxRefundVo); + return thirdRefundVo; + } catch (WxPayException e) { + log.error("微信支付:退款调用异常,payId:{},refundNo:{},error{}", bo.getPayId(),bo.getRefundNo(),e.getMessage()); + thirdRefundVo.setThirdCode(e.getErrCode()); + thirdRefundVo.setThirdMsg(e.getErrCodeDes()); + return thirdRefundVo; + } + } + + public static void main(String[] args) { + String st = "2020-12-01T16:18:12+08:00"; + DateTime dateTime = DateUtil.parse(st, DatePattern.UTC_WITH_XXX_OFFSET_PATTERN); + System.out.println(DateUtil.format(dateTime, DatePattern.NORM_DATETIME_PATTERN)); + } } diff --git a/bnyer-services/bnyer-pay/src/main/java/com/bnyer/pay/enums/EnumVerificationKey.java b/bnyer-services/bnyer-pay/src/main/java/com/bnyer/pay/enums/EnumVerificationKey.java index 279434e..2234160 100644 --- a/bnyer-services/bnyer-pay/src/main/java/com/bnyer/pay/enums/EnumVerificationKey.java +++ b/bnyer-services/bnyer-pay/src/main/java/com/bnyer/pay/enums/EnumVerificationKey.java @@ -13,7 +13,7 @@ import lombok.NoArgsConstructor; @NoArgsConstructor @AllArgsConstructor public enum EnumVerificationKey { - VIP("vip", "VipInOrder20230512Key"), + BNYER("bnyer", "BnyerInOrder20230512Key"), ; private String key; private String value; diff --git a/bnyer-services/bnyer-pay/src/main/java/com/bnyer/pay/service/impl/PayInfoServiceImpl.java b/bnyer-services/bnyer-pay/src/main/java/com/bnyer/pay/service/impl/PayInfoServiceImpl.java index eb6a4a2..b560c85 100644 --- a/bnyer-services/bnyer-pay/src/main/java/com/bnyer/pay/service/impl/PayInfoServiceImpl.java +++ b/bnyer-services/bnyer-pay/src/main/java/com/bnyer/pay/service/impl/PayInfoServiceImpl.java @@ -48,22 +48,8 @@ public class PayInfoServiceImpl extends ServiceImpl impl */ @Override public void addPayInfo(AddPayInfoDto dto) { - PayInfo oldPayInfo = payInfoMapper.selectOne(new LambdaQueryWrapper().eq(PayInfo::getPayId, dto.getPayId())); - if (Objects.nonNull(oldPayInfo) && EnumPayStatus.SUCCESS.getStatus() == oldPayInfo.getPayStatus()){ - throw new ServiceException(ResponseEnum.ORDER_REPEAT_PAY); - } - PayInfo payInfo; - if (Objects.isNull(oldPayInfo)){ - payInfo = dto.toEntity(); - }else { - payInfo = dto.toEntity(); - payInfo.setId(oldPayInfo.getId()); - } - if (payInfo.getId() == null){ - payInfoMapper.insert(payInfo); - }else { - payInfoMapper.updateById(payInfo); - } + PayInfo payInfo = dto.toEntity(); + payInfoMapper.insert(payInfo); } /** diff --git a/bnyer-services/bnyer-pay/src/main/java/com/bnyer/pay/service/impl/UnifiedPayServiceImpl.java b/bnyer-services/bnyer-pay/src/main/java/com/bnyer/pay/service/impl/UnifiedPayServiceImpl.java index ec9fe52..7ec9609 100644 --- a/bnyer-services/bnyer-pay/src/main/java/com/bnyer/pay/service/impl/UnifiedPayServiceImpl.java +++ b/bnyer-services/bnyer-pay/src/main/java/com/bnyer/pay/service/impl/UnifiedPayServiceImpl.java @@ -1,5 +1,8 @@ package com.bnyer.pay.service.impl; +import cn.hutool.core.date.DatePattern; +import cn.hutool.core.date.DateUtil; +import cn.hutool.core.util.ObjectUtil; import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import com.bnyer.common.core.domain.PayInfo; import com.bnyer.common.core.domain.R; @@ -15,6 +18,7 @@ import com.bnyer.order.api.bean.query.VipOrderExtQuery; import com.bnyer.order.api.bean.vo.VipOrderVo; import com.bnyer.order.api.remote.RemoteVipOrderService; import com.bnyer.pay.bean.bo.QueryOrderBo; +import com.bnyer.pay.bean.bo.RefundBo; import com.bnyer.pay.bean.bo.UnifiedOrderBo; import com.bnyer.pay.bean.dto.AddPayInfoDto; import com.bnyer.pay.bean.dto.QueryOrderDto; @@ -31,6 +35,7 @@ import com.bnyer.pay.enums.EnumWxPayStatus; import com.bnyer.pay.mapper.PayInfoMapper; import com.bnyer.pay.service.PayInfoService; import com.bnyer.pay.service.UnifiedPayService; +import com.bnyer.pay.utils.MoneyUtil; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; @@ -169,7 +174,7 @@ public class UnifiedPayServiceImpl implements UnifiedPayService { private UnifiedOrderBo buildUnifiedOrderDto(UnifiedOrderDto dto, String goodsDesc, int goodsType, String payAmount, String payId, HttpServletRequest request) { UserInfoVo userInfo = SecurityUtils.getUserInfo(); String openId = dto.getOpenId(); - if (StringUtils.isBlank(dto.getOpenId())){ + if (StringUtils.isBlank(openId)){ openId = userInfo.getOpenId(); } //当前时间 @@ -249,9 +254,89 @@ public class UnifiedPayServiceImpl implements UnifiedPayService { } } + /** + * 退款 + * @param dto + */ @Override public void refund(RefundDto dto) { + String payId = dto.getPayId(); + PayInfo payInfo = getPayInfoByPayId(payId); + if (Objects.isNull(payInfo) || EnumPayStatus.FAILS.getStatus() == payInfo.getPayStatus()){ + throw new ServiceException("支付订单数据有误,请联系管理员!"); + } + int refundFen = Integer.parseInt(MoneyUtil.yuanToFen(dto.getRefundAmount().toString())); + int payAmountFen = Integer.parseInt(MoneyUtil.yuanToFen(payInfo.getPayAmount().toString())); + if (refundFen > payAmountFen){ + throw new ServiceException("退款金额大于支付金额,无法退款,请联系管理员!"); + } + String refundNo = dto.getPayId() + "Re"; + PayInfo refundOrder = getPayInfoByPayId(refundNo); + if (Objects.nonNull(refundOrder) && EnumRefundStatus.SUCCESS.getStatus() == refundOrder.getRefundStatus()){ + throw new ServiceException("该订单已退款,请勿重复操作!"); + } + //调用第三方退款接口 + IPayStrategy strategy = PayFactory.getInstance().getConcreteStrategy(payInfo.getPayType()); + if (Objects.isNull(strategy)){ + throw new ServiceException("暂不支持该支付方式的退款!"); + } + RefundBo refundBo = buildUnifiedRefundBo(payInfo); + ThirdRefundVo thirdRefundVo = strategy.refund(refundBo); + //保存退款单信息 + if (Objects.isNull(refundOrder)){ + refundOrder = buildRefundOrder(thirdRefundVo,payInfo,dto); + } + //第三方下单返回 + refundOrder.setThirdCode(thirdRefundVo.getThirdCode()); + refundOrder.setThirdMsg(thirdRefundVo.getThirdMsg()); + refundOrder.setThirdNo(thirdRefundVo.getThirdNo()); + refundOrder.setRefundStatus(ObjectUtil.equal(thirdRefundVo.getThirdCode(),"0")?1002:1000); + payInfoMapper.insert(refundOrder); + if (!"0".equals(thirdRefundVo.getThirdCode())){ + throw new ServiceException(thirdRefundVo.getThirdMsg()); + } + } + /** + * 构建退款订单 + * @param thirdRefundVo + * @param payInfo + * @param refundDto + */ + private PayInfo buildRefundOrder(ThirdRefundVo thirdRefundVo, PayInfo payInfo, RefundDto refundDto) { + PayInfo refundOrder = new PayInfo(); + refundOrder.setRefundNo(refundDto.getPayId() + "Re"); + refundOrder.setOrderNo(payInfo.getOrderNo()); + refundOrder.setPayId(payInfo.getPayId()); + refundOrder.setAppid(payInfo.getAppid()); + refundOrder.setPayAmount(payInfo.getPayAmount()); + refundOrder.setRefundAmount(refundDto.getRefundAmount()); + if (StringUtils.isNotBlank(thirdRefundVo.getSuccessTime())){ + refundOrder.setRefundTime(DateUtil.parse(thirdRefundVo.getSuccessTime(), DatePattern.NORM_DATETIME_PATTERN)); + } + return refundOrder; + } + + + /** + * 构建统一退款请求实体 + * @param payInfo + * @return + */ + private RefundBo buildUnifiedRefundBo(PayInfo payInfo) { + RefundBo refundBo = new RefundBo(); + refundBo.setAppId(payInfo.getAppid()); + return refundBo; + } + + /** + * 通过支付单号/退款单号查询订单 + * @param payId + * @return + */ + private PayInfo getPayInfoByPayId(String payId) { + PayInfo payInfo = payInfoMapper.selectOne(new LambdaQueryWrapper().eq(PayInfo::getPayId, payId)); + return payInfo; } } diff --git a/bnyer-services/bnyer-pay/src/main/java/com/bnyer/pay/utils/PaymentRefundUtil.java b/bnyer-services/bnyer-pay/src/main/java/com/bnyer/pay/utils/PaymentRefundUtil.java index cadee6e..5d04337 100644 --- a/bnyer-services/bnyer-pay/src/main/java/com/bnyer/pay/utils/PaymentRefundUtil.java +++ b/bnyer-services/bnyer-pay/src/main/java/com/bnyer/pay/utils/PaymentRefundUtil.java @@ -17,7 +17,7 @@ public class PaymentRefundUtil { * @return */ public static String getSign(RefundDto dto) { - return MD5Util.getMD5String(dto.getPayId() + EnumVerificationKey.VIP.getValue()); + return MD5Util.getMD5String(dto.getPayId() + EnumVerificationKey.BNYER.getValue()); } /** @@ -27,13 +27,13 @@ public class PaymentRefundUtil { */ public static boolean checkSign(RefundDto dto) { - return MD5Util.getMD5String(dto.getPayId() + EnumVerificationKey.VIP.getValue()).equals(dto.getSign()); + return MD5Util.getMD5String(dto.getPayId() + EnumVerificationKey.BNYER.getValue()).equals(dto.getSign()); } public static void main(String[] args) { - String sign = MD5Util.getMD5String("RVWU202305121022211042" + EnumVerificationKey.VIP.getValue()); + String sign = MD5Util.getMD5String("RVWU202305121022211042" + EnumVerificationKey.BNYER.getValue()); System.out.println(sign); - System.out.println(MD5Util.getMD5String("RVWU202305121022211042" + EnumVerificationKey.VIP.getValue()).equals(sign)); + System.out.println(MD5Util.getMD5String("RVWU202305121022211042" + EnumVerificationKey.BNYER.getValue()).equals(sign)); } }