Browse Source

添加统一订单查询

feature-1.1
wuxicheng 3 years ago
parent
commit
216c86cce6
  1. 10
      bnyer-common/bnyer-common-core/src/main/java/com/bnyer/common/core/enums/EnumPayStatus.java
  2. 7
      bnyer-common/bnyer-common-core/src/main/java/com/bnyer/common/core/enums/EnumPayType.java
  3. 1
      bnyer-common/bnyer-common-core/src/main/java/com/bnyer/common/core/enums/ResponseEnum.java
  4. 2
      bnyer-services/bnyer-order/src/main/java/com/bnyer/order/service/impl/VipOrderServiceImpl.java
  5. 30
      bnyer-services/bnyer-pay/src/main/java/com/bnyer/pay/bo/QueryOrderBo.java
  6. 6
      bnyer-services/bnyer-pay/src/main/java/com/bnyer/pay/bo/UnifiedOrderBo.java
  7. 4
      bnyer-services/bnyer-pay/src/main/java/com/bnyer/pay/constant/DYPayConstants.java
  8. 6
      bnyer-services/bnyer-pay/src/main/java/com/bnyer/pay/constant/KSPayConstants.java
  9. 20
      bnyer-services/bnyer-pay/src/main/java/com/bnyer/pay/controller/PayInfoController.java
  10. 49
      bnyer-services/bnyer-pay/src/main/java/com/bnyer/pay/controller/UnifiedPayController.java
  11. 34
      bnyer-services/bnyer-pay/src/main/java/com/bnyer/pay/design/strategy/AliPayStrategy.java
  12. 194
      bnyer-services/bnyer-pay/src/main/java/com/bnyer/pay/design/strategy/DYPayStrategy.java
  13. 15
      bnyer-services/bnyer-pay/src/main/java/com/bnyer/pay/design/strategy/IPayStrategy.java
  14. 190
      bnyer-services/bnyer-pay/src/main/java/com/bnyer/pay/design/strategy/KSPayStrategy.java
  15. 99
      bnyer-services/bnyer-pay/src/main/java/com/bnyer/pay/design/strategy/WxPayStrategy.java
  16. 72
      bnyer-services/bnyer-pay/src/main/java/com/bnyer/pay/dto/AddPayInfoDto.java
  17. 39
      bnyer-services/bnyer-pay/src/main/java/com/bnyer/pay/dto/InOrderDto.java
  18. 33
      bnyer-services/bnyer-pay/src/main/java/com/bnyer/pay/dto/QueryOrderDto.java
  19. 37
      bnyer-services/bnyer-pay/src/main/java/com/bnyer/pay/enums/EnumDyPayStatus.java
  20. 37
      bnyer-services/bnyer-pay/src/main/java/com/bnyer/pay/enums/EnumKsPayStatus.java
  21. 37
      bnyer-services/bnyer-pay/src/main/java/com/bnyer/pay/enums/EnumWxPayStatus.java
  22. 15
      bnyer-services/bnyer-pay/src/main/java/com/bnyer/pay/service/PayInfoService.java
  23. 31
      bnyer-services/bnyer-pay/src/main/java/com/bnyer/pay/service/UnifiedPayService.java
  24. 127
      bnyer-services/bnyer-pay/src/main/java/com/bnyer/pay/service/impl/PayInfoServiceImpl.java
  25. 209
      bnyer-services/bnyer-pay/src/main/java/com/bnyer/pay/service/impl/UnifiedPayServiceImpl.java
  26. 131
      bnyer-services/bnyer-pay/src/main/java/com/bnyer/pay/utils/MoneyUtil.java
  27. 19
      bnyer-services/bnyer-pay/src/main/java/com/bnyer/pay/vo/PayInfoDetailsVo.java
  28. 86
      bnyer-services/bnyer-pay/src/main/java/com/bnyer/pay/vo/PayInfoVo.java
  29. 22
      bnyer-services/bnyer-pay/src/main/java/com/bnyer/pay/vo/QueryOrderVo.java
  30. 8
      bnyer-services/bnyer-pay/src/main/java/com/bnyer/pay/vo/ThirdInOrderVo.java
  31. 42
      bnyer-services/bnyer-pay/src/main/java/com/bnyer/pay/vo/ThirdQueryOrderVo.java
  32. 4
      bnyer-services/bnyer-pay/src/main/resources/com/bnyer/pay/mapper/PayInfoMapper.xml

10
bnyer-common/bnyer-common-core/src/main/java/com/bnyer/common/core/enums/EnumPayStatus.java

@ -3,6 +3,8 @@ package com.bnyer.common.core.enums;
import lombok.AllArgsConstructor;
import lombok.Getter;
import java.util.Arrays;
/**
* @author :WXC
* @description :
@ -16,8 +18,14 @@ public enum EnumPayStatus {
FAILS(1002,"支付失败"),
;
private final int code;
private final int status;
private final String name;
public static EnumPayStatus getEnumPayStatusByStatus(int status) {
return Arrays.stream(values())
.filter(payStatus -> payStatus.getStatus() == status)
.findFirst().orElseThrow(() -> new SecurityException("status 未匹配上对应的支付状态"));
}
}

7
bnyer-common/bnyer-common-core/src/main/java/com/bnyer/common/core/enums/EnumPayType.java

@ -3,6 +3,7 @@ package com.bnyer.common.core.enums;
import lombok.AllArgsConstructor;
import lombok.Getter;
import java.util.Arrays;
import java.util.Objects;
/**
@ -32,4 +33,10 @@ public enum EnumPayType {
return null;
}
public static EnumPayType getEnumPayTypeByType(String type) {
return Arrays.stream(values())
.filter(payType -> Objects.equals(payType.getType(), type))
.findFirst().orElseThrow(() -> new SecurityException("type 未匹配上对应的支付方式"));
}
}

1
bnyer-common/bnyer-common-core/src/main/java/com/bnyer/common/core/enums/ResponseEnum.java

@ -32,6 +32,7 @@ public enum ResponseEnum {
//======================第三方接口调用异常========================
PAY_FAILS(220001,"支付失败,请稍后重试"),
ORDER_QUERY_FAILS(220002,"订单查询失败,请稍后重试"),
;

2
bnyer-services/bnyer-order/src/main/java/com/bnyer/order/service/impl/VipOrderServiceImpl.java

@ -185,7 +185,7 @@ public class VipOrderServiceImpl extends ServiceImpl<VipOrderMapper, VipOrder> i
@Transactional(rollbackFor = Exception.class)
@Override
public void updateByToPaySuccess(VipOrder vipOrder) {
vipOrder.setPayStatus(EnumPayStatus.SUCCESS.getCode());
vipOrder.setPayStatus(EnumPayStatus.SUCCESS.getStatus());
vipOrder.setOrderStatus(EnumVipOrderStatus.SUCCESS.getStatus());
vipOrder.setUpdateTime(new Date());
vipOrder.setPayTime(new Date());

30
bnyer-services/bnyer-pay/src/main/java/com/bnyer/pay/bo/QueryOrderBo.java

@ -0,0 +1,30 @@
package com.bnyer.pay.bo;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
/**
* @author :WXC
* @Date :2023/05/05
* @description :
*/
@Getter
@Setter
@NoArgsConstructor
public class QueryOrderBo {
/**
* 支付类型wxpay/alipay/kspay/dypay
*/
private String payType;
/**
* 交易类型 1--JSAPI支付小程序appId支付2--Native支付3--app支付4--JSAPI支付公众号appId支付5--H5支付,微信支付必填
*/
private String tradeType;
/**
* 支付单号
*/
private String payId;
}

6
bnyer-services/bnyer-pay/src/main/java/com/bnyer/pay/dto/UnifiedOrderDto.java → bnyer-services/bnyer-pay/src/main/java/com/bnyer/pay/bo/UnifiedOrderBo.java

@ -1,4 +1,4 @@
package com.bnyer.pay.dto;
package com.bnyer.pay.bo;
import lombok.Getter;
import lombok.NoArgsConstructor;
@ -14,7 +14,7 @@ import java.util.Date;
@Getter
@Setter
@NoArgsConstructor
public class UnifiedOrderDto {
public class UnifiedOrderBo {
/**
* 内部支付单号
@ -37,7 +37,7 @@ public class UnifiedOrderDto {
*/
private Date currDate;
/**
* 交易类型 1--JSAPI支付小程序appId支付2--Native支付3--app支付4--JSAPI支付公众号appId支付 6-H5支付 ,必要参数
* 交易类型 1--JSAPI支付小程序appId支付2--Native支付3--app支付4--JSAPI支付公众号appId支付5--H5支付,微信支付必填
*/
private String tradeType;
/**

4
bnyer-services/bnyer-pay/src/main/java/com/bnyer/pay/constant/DYPayConstants.java

@ -14,6 +14,10 @@ public class DYPayConstants {
* 生成预支付单
*/
public static final String CREATE_ORDER = "https://developer.toutiao.com/api/apps/ecpay/v1/create_order";
/**
* 查询订单
*/
public static final String QUERY_ORDER = "https://developer.toutiao.com/api/apps/ecpay/v1/query_order";
/**
* 分账
*/

6
bnyer-services/bnyer-pay/src/main/java/com/bnyer/pay/constant/KSPayConstants.java

@ -24,6 +24,12 @@ public class KSPayConstants {
*/
public static final String CREATE_ORDER = "https://open.kuaishou.com/openapi/mp/developer/epay/create_order";
/**
* https://mp.kuaishou.com/docs/develop/server/epay/interfaceDefinition.html
* 订单查询接口
*/
public static final String QUERY_ORDER = "https://open.kuaishou.com/openapi/mp/developer/epay/query_order";
/**
* 退款
* https://mp.kuaishou.com/docs/develop/server/epay/interfaceDefinition.html#_1-3%E6%94%AF%E4%BB%98%E5%9B%9E%E8%B0%83

20
bnyer-services/bnyer-pay/src/main/java/com/bnyer/pay/controller/PayInfoController.java

@ -1,21 +1,10 @@
package com.bnyer.pay.controller;
import com.bnyer.common.core.domain.R;
import com.bnyer.pay.dto.AddPayInfoDto;
import com.bnyer.pay.service.PayInfoService;
import com.bnyer.pay.vo.PayInOrderVo;
import io.swagger.annotations.Api;
import io.swagger.v3.oas.annotations.Operation;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import javax.servlet.http.HttpServletRequest;
import javax.validation.Valid;
/**
* @author :WXC
* @Date :2023/04/03
@ -26,14 +15,5 @@ import javax.validation.Valid;
@RequestMapping("/payinfo")
@Slf4j
public class PayInfoController {
@Autowired
private PayInfoService payInfoService;
@PostMapping("/addPayInOrder")
@Operation(summary = "统一下单,并生成支付订单" , description = "生成支付订单,返回前端支付所需参数")
public R<PayInOrderVo> addPayInOrder(@Valid @RequestBody AddPayInfoDto dto, HttpServletRequest request){
PayInOrderVo payInOrderVo = payInfoService.addPayInOrder(dto,request);
return R.ok(payInOrderVo);
}
}

49
bnyer-services/bnyer-pay/src/main/java/com/bnyer/pay/controller/UnifiedPayController.java

@ -0,0 +1,49 @@
package com.bnyer.pay.controller;
import com.bnyer.common.core.domain.R;
import com.bnyer.pay.dto.InOrderDto;
import com.bnyer.pay.dto.QueryOrderDto;
import com.bnyer.pay.service.UnifiedPayService;
import com.bnyer.pay.vo.QueryOrderVo;
import com.bnyer.pay.vo.ThirdInOrderVo;
import io.swagger.annotations.Api;
import io.swagger.v3.oas.annotations.Operation;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import javax.servlet.http.HttpServletRequest;
import javax.validation.Valid;
/**
* @author :WXC
* @Date :2023/05/05
* @description :
*/
@Api(value = "统一支付相关接口",tags = "统一支付相关接口")
@RestController
@RequestMapping("/unified")
@Slf4j
public class UnifiedPayController {
@Autowired
private UnifiedPayService unifiedPayService;
@PostMapping("/inOrder")
@Operation(summary = "统一下单,并生成支付订单" , description = "生成支付订单,返回前端支付所需参数")
public R<ThirdInOrderVo> inOrder(@Valid @RequestBody InOrderDto dto, HttpServletRequest request){
ThirdInOrderVo thirdInOrderVo = unifiedPayService.inOrder(dto,request);
return R.ok(thirdInOrderVo);
}
@PostMapping("/queryOrder")
@Operation(summary = "统一订单查询" , description = "订单查询,查询支付结果")
public R<QueryOrderVo> queryOrder(@Valid @RequestBody QueryOrderDto dto){
QueryOrderVo queryOrderVo = unifiedPayService.queryOrder(dto);
return R.ok(queryOrderVo);
}
}

34
bnyer-services/bnyer-pay/src/main/java/com/bnyer/pay/design/strategy/AliPayStrategy.java

@ -19,23 +19,21 @@ import com.bnyer.common.core.enums.EnumTimeUnit;
import com.bnyer.common.core.enums.ResponseEnum;
import com.bnyer.common.core.exception.ServiceException;
import com.bnyer.common.core.utils.DateUtils;
import com.bnyer.common.core.utils.SpringUtils;
import com.bnyer.common.core.utils.StringUtils;
import com.bnyer.pay.bo.QueryOrderBo;
import com.bnyer.pay.constant.AliPayConstant;
import com.bnyer.pay.dto.EditPayInfoNotifyDto;
import com.bnyer.pay.dto.PayNotifyCheckDto;
import com.bnyer.pay.dto.UnifiedOrderDto;
import com.bnyer.pay.bo.UnifiedOrderBo;
import com.bnyer.pay.enums.EnumPayChannel;
import com.bnyer.pay.enums.EnumPayConfigStatus;
import com.bnyer.pay.mapper.AlipayConfigMapper;
import com.bnyer.pay.service.PayInfoService;
import com.bnyer.pay.vo.PayInOrderVo;
import com.bnyer.pay.vo.ThirdInOrderVo;
import com.bnyer.pay.vo.ThirdQueryOrderVo;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.transaction.interceptor.TransactionAspectSupport;
import javax.annotation.Resource;
import java.util.HashMap;
@ -57,10 +55,9 @@ public class AliPayStrategy extends AbstractPayStrategy {
@Autowired
private PayInfoService payInfoService;
@Transactional(propagation = Propagation.REQUIRED,rollbackFor=Exception.class)
@Override
public PayInOrderVo unifiedOrder(UnifiedOrderDto dto) {
log.info("支付宝支付:统一下单接口调用开始,AliPayStrategy.unifiedOrder dto:{}", JSON.toJSONString(dto));
public ThirdInOrderVo unifiedOrder(UnifiedOrderBo bo) {
log.info("支付宝支付:统一下单接口调用开始,AliPayStrategy.unifiedOrder bo:{}", JSON.toJSONString(bo));
List<AlipayConfig> alipayConfigList = alipayConfigMapper.selectList(new LambdaQueryWrapper<AlipayConfig>().eq(AlipayConfig::getStatus, EnumPayConfigStatus.ENABLE.getCode()));
if (CollUtil.isEmpty(alipayConfigList)){
throw new ServiceException(ResponseEnum.PAY_CONFIG_ERROR);
@ -77,24 +74,24 @@ public class AliPayStrategy extends AbstractPayStrategy {
AlipayTradeAppPayRequest request = new AlipayTradeAppPayRequest();
// SDK已经封装掉了公共参数,这里只需要传入业务参数。以下方法为sdk的model入参方式(model和biz_content同时存在的情况下取biz_content)。
AlipayTradeAppPayModel model = new AlipayTradeAppPayModel();
model.setSubject(dto.getGoodsSubject());
model.setBody(dto.getGoodsDesc());
model.setOutTradeNo(dto.getPayId());
model.setSubject(bo.getGoodsSubject());
model.setBody(bo.getGoodsDesc());
model.setOutTradeNo(bo.getPayId());
//直接固定好过期时间比较好
model.setTimeExpire(DateUtil.formatDateTime(DateUtils.getDateByType(EnumTimeUnit.MINUTE,dto.getCurrDate(),30)));
model.setTimeExpire(DateUtil.formatDateTime(DateUtils.getDateByType(EnumTimeUnit.MINUTE,bo.getCurrDate(),30)));
// model.setTimeoutExpress(AliPayConstant.timeoutExpress);
//元
model.setTotalAmount(dto.getPayAmount());
model.setTotalAmount(bo.getPayAmount());
request.setBizModel(model);
request.setNotifyUrl(backurl);
try {
// 这里和普通的接口调用不同,使用的是sdkExecute
AlipayTradeAppPayResponse response = alipayClient.sdkExecute(request);
if(response.isSuccess()){
PayInOrderVo vo = new PayInOrderVo();
ThirdInOrderVo vo = new ThirdInOrderVo();
vo.setOutStr(response.getBody());
vo.setAppid(appid);
vo.setPayId(dto.getPayId());
vo.setOutOrderNo(bo.getPayId());
return vo;
}else{
throw new ServiceException(response.getMsg());
@ -173,5 +170,10 @@ public class AliPayStrategy extends AbstractPayStrategy {
return MsgConstants.SUCCESS;
}
@Override
public ThirdQueryOrderVo queryOrder(QueryOrderBo bo) {
return null;
}
}

194
bnyer-services/bnyer-pay/src/main/java/com/bnyer/pay/design/strategy/DYPayStrategy.java

@ -4,37 +4,33 @@ import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.date.DateUtil;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.alibaba.fastjson.serializer.SerializerFeature;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.bnyer.common.core.context.SecurityContextHolder;
import com.bnyer.common.core.domain.DypayConfig;
import com.bnyer.common.core.domain.KspayConfig;
import com.bnyer.common.core.enums.EnumPayType;
import com.bnyer.common.core.enums.ResponseEnum;
import com.bnyer.common.core.exception.ServiceException;
import com.bnyer.common.core.utils.StringUtils;
import com.bnyer.pay.bo.QueryOrderBo;
import com.bnyer.pay.constant.DYPayConstants;
import com.bnyer.pay.constant.KSPayConstants;
import com.bnyer.pay.dto.EditPayInfoNotifyDto;
import com.bnyer.pay.dto.PayNotifyCheckDto;
import com.bnyer.pay.dto.UnifiedOrderDto;
import com.bnyer.pay.bo.UnifiedOrderBo;
import com.bnyer.pay.enums.EnumPayChannel;
import com.bnyer.pay.enums.EnumPayConfigStatus;
import com.bnyer.pay.mapper.DypayConfigMapper;
import com.bnyer.pay.mapper.KspayConfigMapper;
import com.bnyer.pay.service.PayInfoService;
import com.bnyer.pay.utils.DYPayUtil;
import com.bnyer.pay.utils.KSPayUtil;
import com.bnyer.pay.utils.MoneyUtil;
import com.bnyer.pay.utils.PayRestTemplateUtil;
import com.bnyer.pay.vo.PayInOrderVo;
import com.bnyer.pay.vo.ThirdInOrderVo;
import com.bnyer.pay.vo.ThirdQueryOrderVo;
import com.github.binarywang.wxpay.bean.request.BaseWxPayRequest;
import com.github.binarywang.wxpay.bean.result.BaseWxPayResult;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.codec.digest.DigestUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import java.math.BigDecimal;
import java.util.Date;
import java.util.List;
import java.util.Map;
@ -61,14 +57,24 @@ public class DYPayStrategy extends AbstractPayStrategy{
@Autowired
private DypayConfigMapper dypayConfigMapper;
/**
* 查询支付配置
* @return
*/
private DypayConfig getDypayConfig() {
List<DypayConfig> dypayConfigList = dypayConfigMapper.selectList(new LambdaQueryWrapper<DypayConfig>().eq(DypayConfig::getStatus, EnumPayConfigStatus.ENABLE.getCode()));
if (CollUtil.isEmpty(dypayConfigList)){
throw new ServiceException(ResponseEnum.PAY_CONFIG_ERROR);
}
DypayConfig dypayConfig = dypayConfigList.get(0);
return dypayConfig;
}
@Override
public PayInOrderVo unifiedOrder(UnifiedOrderDto dto) {
public ThirdInOrderVo unifiedOrder(UnifiedOrderBo bo) {
String result = "";
try {
List<DypayConfig> dypayConfigList = dypayConfigMapper.selectList(new LambdaQueryWrapper<DypayConfig>().eq(DypayConfig::getStatus, EnumPayConfigStatus.ENABLE.getCode()));
if (CollUtil.isEmpty(dypayConfigList)){
throw new ServiceException(ResponseEnum.PAY_CONFIG_ERROR);
}
DypayConfig dypayConfig = dypayConfigList.get(0);
DypayConfig dypayConfig = getDypayConfig();
String appId = dypayConfig.getAppid();
String backurl = dypayConfig.getBackurl();
String salt = dypayConfig.getSalt();
@ -77,13 +83,13 @@ public class DYPayStrategy extends AbstractPayStrategy{
//小程序APPID
params.put("app_id",appId);
//开发者侧的订单号。需保证同一小程序下不可重复
params.put("out_order_no", dto.getPayId());
params.put("out_order_no", bo.getPayId());
//支付价格。单位为[分],取值范围:[1,10000000000] 100元 = 100*100 分
params.put("total_amount", BaseWxPayRequest.yuanToFen(dto.getPayAmount()));
params.put("total_amount", BaseWxPayRequest.yuanToFen(bo.getPayAmount()));
//商品描述。
params.put("subject", dto.getGoodsSubject());
params.put("subject", bo.getGoodsSubject());
//商品详情
params.put("body", dto.getGoodsDesc());
params.put("body", bo.getGoodsDesc());
//订单过期时间(秒) 5min-2day
params.put("valid_time", 1800);
//开发者自定义字段,回调原样回传。超过最大长度会被截断
@ -97,63 +103,55 @@ public class DYPayStrategy extends AbstractPayStrategy{
//以JSON格式拼好以下参数发送请求
JSONObject payJson = new JSONObject();
payJson.put("app_id", appId);
payJson.put("out_order_no", dto.getPayId());
payJson.put("out_order_no", bo.getPayId());
//此处需要传入一个数值类型,string会报错。。
payJson.put("total_amount", BaseWxPayRequest.yuanToFen(dto.getPayAmount()));
payJson.put("subject",dto.getGoodsSubject());
payJson.put("body", dto.getGoodsDesc());
payJson.put("total_amount", BaseWxPayRequest.yuanToFen(bo.getPayAmount()));
payJson.put("subject",bo.getGoodsSubject());
payJson.put("body", bo.getGoodsDesc());
payJson.put("valid_time", 1800);
payJson.put("sign", sign);
//payJson.put("cp_extra", "开发者自定义字段");
payJson.put("notify_url",backurl);
log.info("请求参数{}", payJson);
//预下单接口
String result = payRestTemplateUtil.dyPostRequest(payJson, DYPayConstants.CREATE_ORDER);
log.info("==================================");
log.info("抖音预下单result{}", result);
log.info("==================================");
if (!"".equals(result)) {
JSONObject jsonObject = JSONObject.parseObject(result);
String errNo = jsonObject.getString("err_no");
if ("0".equals(errNo)) {
JSONObject data = jsonObject.getJSONObject("data");
String orderId = data.getString("order_id");
String orderToken = data.getString("order_token");
if (null != orderToken && null != orderId) {
//保存预下单信息
PayInOrderVo payInOrderVo = new PayInOrderVo();
//把order_no和order_info_token返回前端用于调起收银台
payInOrderVo.setPayId(dto.getPayId());
payInOrderVo.setPayOrderId(orderId);
payInOrderVo.setOrderToken(orderToken);
return payInOrderVo;
} else {
log.error("抖音支付:统一下单接口调用失败,payId:{},result:{},error{}", dto.getPayId(),JSON.toJSONString(data), "返回信息为空");
throw new ServiceException(ResponseEnum.PAY_FAILS);
}
} else {
log.error("抖音支付:统一下单接口调用失败,payId:{},error{}", dto.getPayId(), jsonObject.getString("error_msg"));
throw new ServiceException(ResponseEnum.PAY_FAILS);
}
} else {
log.error("抖音支付:统一下单接口调用失败,payId:{},error{}", dto.getPayId(), "请求结果返回为空");
throw new ServiceException(ResponseEnum.PAY_FAILS);
}
result = payRestTemplateUtil.dyPostRequest(payJson, DYPayConstants.CREATE_ORDER);
} catch (Exception e) {
e.printStackTrace();
log.error("抖音支付:支付异常,payId:{},error{}", dto.getPayId(), e.getMessage());
log.error("抖音支付:支付异常,payId:{},error{}", bo.getPayId(), e.getMessage());
throw new ServiceException(ResponseEnum.PAY_FAILS);
}
log.info("==================================");
log.info("抖音预下单result{}", result);
log.info("==================================");
if (StringUtils.isBlank(result)){
log.error("抖音支付:统一下单接口调用失败,payId:{},error{}", bo.getPayId(), "请求结果返回为空");
throw new ServiceException(ResponseEnum.PAY_FAILS);
}
JSONObject jsonObject = JSONObject.parseObject(result);
String errNo = jsonObject.getString("err_no");
if (!"0".equals(errNo)) {
log.error("抖音支付:统一下单接口调用失败,payId:{},error{}", bo.getPayId(), jsonObject.getString("error_msg"));
throw new ServiceException(ResponseEnum.PAY_FAILS);
}
JSONObject data = jsonObject.getJSONObject("data");
String orderId = data.getString("order_id");
String orderToken = data.getString("order_token");
if (StringUtils.isBlank(orderId) || StringUtils.isBlank(orderToken)){
log.error("抖音支付:统一下单接口调用失败,payId:{},result:{},error{}", bo.getPayId(),JSON.toJSONString(data), "返回信息为空");
throw new ServiceException(ResponseEnum.PAY_FAILS);
}
//保存预下单信息
ThirdInOrderVo thirdInOrderVo = new ThirdInOrderVo();
//把order_no和order_info_token返回前端用于调起收银台
thirdInOrderVo.setOutOrderNo(bo.getPayId());
thirdInOrderVo.setThirdOrderNo(orderId);
thirdInOrderVo.setOrderToken(orderToken);
return thirdInOrderVo;
}
@Override
public String parsePayNotify(String params) {
List<DypayConfig> dypayConfigList = dypayConfigMapper.selectList(new LambdaQueryWrapper<DypayConfig>()
.eq(DypayConfig::getStatus, EnumPayConfigStatus.ENABLE.getCode()));
if (CollUtil.isEmpty(dypayConfigList)){
throw new ServiceException(ResponseEnum.PAY_CONFIG_ERROR);
}
DypayConfig dypayConfig = dypayConfigList.get(0);
DypayConfig dypayConfig = getDypayConfig();
String appId = dypayConfig.getAppid();
String token = dypayConfig.getToken();
JSONObject object = JSONObject.parseObject(params);
@ -196,7 +194,7 @@ public class DYPayStrategy extends AbstractPayStrategy{
}
log.info("抖音支付回调,交易正常:封装参数修改内部支付单信息");
EditPayInfoNotifyDto editPayInfoNotifyDto = new EditPayInfoNotifyDto();
editPayInfoNotifyDto.setPayAmount(BaseWxPayResult.fenToYuan(totalAmount));
editPayInfoNotifyDto.setPayAmount(MoneyUtil.fenToYuan(String.valueOf(totalAmount)));
editPayInfoNotifyDto.setPayTime(DateUtil.formatDateTime(new Date()));
editPayInfoNotifyDto.setAppId(appId);
editPayInfoNotifyDto.setPayId(outOrderNo);
@ -214,4 +212,76 @@ public class DYPayStrategy extends AbstractPayStrategy{
}
return super.buildNotifyCheckResultMsg(EnumPayType.DY_PAY,true,"business fail");
}
@Override
public ThirdQueryOrderVo queryOrder(QueryOrderBo bo) {
DypayConfig dypayConfig = getDypayConfig();
String appId = dypayConfig.getAppid();
String salt = dypayConfig.getSalt();
String result = "";
try {
//加签验签的参数需要排序
Map<String, Object> params = new TreeMap<>();
//小程序APPID
params.put("app_id", appId);
//开发者侧的订单号。需保证同一小程序下不可重复
params.put("out_order_no", bo.getPayId());
//签名
String sign = dyPayUtil.getSign(params, salt);
JSONObject queryOrderJson = new JSONObject();
queryOrderJson.put("app_id", appId);
queryOrderJson.put("out_order_no", bo.getPayId());
queryOrderJson.put("sign", sign);
//发起请求
result = payRestTemplateUtil.dyPostRequest(queryOrderJson, DYPayConstants.QUERY_ORDER);
}catch (Exception e){
e.printStackTrace();
log.error("抖音支付:订单查询异常,payId:{},error{}", bo.getPayId(), e.getMessage());
throw new ServiceException(ResponseEnum.ORDER_QUERY_FAILS);
}
log.info("==================================");
log.info("抖音订单查询result{}", result);
log.info("==================================");
if (StringUtils.isBlank(result)) {
log.error("抖音支付:订单查询异常,payId:{},error{}", bo.getPayId(), "请求结果返回为空");
throw new ServiceException(ResponseEnum.ORDER_QUERY_FAILS);
}
JSONObject jsonObject = JSONObject.parseObject(result);
String errNo = jsonObject.getString("err_no");
if (!"0".equals(errNo)) {
log.error("抖音支付:订单查询异常,payId:{},error{}", bo.getPayId(), jsonObject.getString("err_tips"));
throw new ServiceException(ResponseEnum.ORDER_QUERY_FAILS);
}
//开发者下单单号
String outOrderNo = jsonObject.getString("out_order_no");
//抖音侧的订单号
String orderId = jsonObject.getString("order_id");
//详细信息
JSONObject data = jsonObject.getJSONObject("payment_info");
//支付状态:SUCCESS:成功 TIMEOUT:超时未支付 PROCESSING:处理中 FAIL:失败
String payStatus = data.getString("order_status");
//预下单用户支付金额
Integer totalAmount = data.getInteger("total_amount");
//预下单用户支付金额
String payTime = data.getString("pay_time");
//支付渠道, 1-微信支付,2-支付宝支付,10-抖音支付
Integer payChannel = data.getInteger("way");
//开发者回传的订单同步状态
String orderStatus = data.getString("order_status");
//抖音小程序平台订单号
String openId = data.getString("open_id");
//支付渠道侧的支付单号
String channelNo = data.getString("channel_no");
ThirdQueryOrderVo thirdQueryOrderVo = new ThirdQueryOrderVo();
thirdQueryOrderVo.setOutOrderNo(outOrderNo);
thirdQueryOrderVo.setPayStatus(payStatus);
thirdQueryOrderVo.setTotalAmount(MoneyUtil.fenToYuan(String.valueOf(totalAmount)));
thirdQueryOrderVo.setPayTime(payTime);
thirdQueryOrderVo.setDyPayChannel(payChannel);
thirdQueryOrderVo.setThirdOrderNo(orderId);
thirdQueryOrderVo.setOrderStatus(orderStatus);
thirdQueryOrderVo.setOpenId(openId);
thirdQueryOrderVo.setChannelNo(channelNo);
return thirdQueryOrderVo;
}
}

15
bnyer-services/bnyer-pay/src/main/java/com/bnyer/pay/design/strategy/IPayStrategy.java

@ -1,7 +1,9 @@
package com.bnyer.pay.design.strategy;
import com.bnyer.pay.dto.UnifiedOrderDto;
import com.bnyer.pay.vo.PayInOrderVo;
import com.bnyer.pay.bo.QueryOrderBo;
import com.bnyer.pay.bo.UnifiedOrderBo;
import com.bnyer.pay.vo.ThirdInOrderVo;
import com.bnyer.pay.vo.ThirdQueryOrderVo;
/**
* @author :WXC
@ -11,10 +13,10 @@ import com.bnyer.pay.vo.PayInOrderVo;
public interface IPayStrategy {
/**
* 统一下单
* @param dto
* @param bo
* @return
*/
PayInOrderVo unifiedOrder(UnifiedOrderDto dto);
ThirdInOrderVo unifiedOrder(UnifiedOrderBo bo);
/**
* 支付回调处理
@ -28,9 +30,12 @@ public interface IPayStrategy {
*/
String parsePayNotify(String params);
/**
* 订单查询
*/
ThirdQueryOrderVo queryOrder(QueryOrderBo bo);
//===========待完成================
// TODO: 2023/04/03 订单查询
// void orderQuery();
// TODO: 2023/04/03 退款
// void refund();

190
bnyer-services/bnyer-pay/src/main/java/com/bnyer/pay/design/strategy/KSPayStrategy.java

@ -1,7 +1,6 @@
package com.bnyer.pay.design.strategy;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.date.DateUtil;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
@ -13,17 +12,20 @@ import com.bnyer.common.core.enums.EnumPayType;
import com.bnyer.common.core.enums.ResponseEnum;
import com.bnyer.common.core.exception.ServiceException;
import com.bnyer.common.core.utils.StringUtils;
import com.bnyer.pay.bo.QueryOrderBo;
import com.bnyer.pay.constant.KSPayConstants;
import com.bnyer.pay.dto.EditPayInfoNotifyDto;
import com.bnyer.pay.dto.PayNotifyCheckDto;
import com.bnyer.pay.dto.UnifiedOrderDto;
import com.bnyer.pay.bo.UnifiedOrderBo;
import com.bnyer.pay.enums.EnumPayChannel;
import com.bnyer.pay.enums.EnumPayConfigStatus;
import com.bnyer.pay.mapper.KspayConfigMapper;
import com.bnyer.pay.service.PayInfoService;
import com.bnyer.pay.utils.KSPayUtil;
import com.bnyer.pay.utils.MoneyUtil;
import com.bnyer.pay.utils.PayRestTemplateUtil;
import com.bnyer.pay.vo.PayInOrderVo;
import com.bnyer.pay.vo.ThirdInOrderVo;
import com.bnyer.pay.vo.ThirdQueryOrderVo;
import com.github.binarywang.wxpay.bean.request.BaseWxPayRequest;
import com.github.binarywang.wxpay.bean.result.BaseWxPayResult;
import lombok.extern.slf4j.Slf4j;
@ -57,14 +59,24 @@ public class KSPayStrategy extends AbstractPayStrategy{
@Autowired
private KspayConfigMapper kspayConfigMapper;
/**
* 查询支付配置
* @return
*/
private KspayConfig getKspayConfig() {
List<KspayConfig> kspayConfigList = kspayConfigMapper.selectList(new LambdaQueryWrapper<KspayConfig>().eq(KspayConfig::getStatus, EnumPayConfigStatus.ENABLE.getCode()));
if (CollUtil.isEmpty(kspayConfigList)){
throw new ServiceException(ResponseEnum.PAY_CONFIG_ERROR);
}
KspayConfig kspayConfig = kspayConfigList.get(0);
return kspayConfig;
}
@Override
public PayInOrderVo unifiedOrder(UnifiedOrderDto dto) {
public ThirdInOrderVo unifiedOrder(UnifiedOrderBo bo) {
String result = "";
try {
List<KspayConfig> kspayConfigList = kspayConfigMapper.selectList(new LambdaQueryWrapper<KspayConfig>().eq(KspayConfig::getStatus, EnumPayConfigStatus.ENABLE.getCode()));
if (CollUtil.isEmpty(kspayConfigList)){
throw new ServiceException(ResponseEnum.PAY_CONFIG_ERROR);
}
KspayConfig kspayConfig = kspayConfigList.get(0);
KspayConfig kspayConfig = getKspayConfig();
String openId = SecurityContextHolder.getFhOpenId();
String appId = kspayConfig.getAppid();
String backurl = kspayConfig.getBackurl();
@ -74,17 +86,17 @@ public class KSPayStrategy extends AbstractPayStrategy{
//小程序APPID
params.put("app_id", appId);
//开发者侧的订单号。需保证同一小程序下不可重复
params.put("out_order_no", dto.getPayId());
params.put("out_order_no", bo.getPayId());
//快手用户在当前小程序的open_id,可通过login操作获取
params.put("open_id", openId);
//用户支付金额,单位为[分]。不允许传非整数的数值。
params.put("total_amount", BaseWxPayRequest.yuanToFen(dto.getPayAmount()));
params.put("total_amount", BaseWxPayRequest.yuanToFen(bo.getPayAmount()));
//商品描述。
params.put("subject", dto.getGoodsSubject());
params.put("subject", bo.getGoodsSubject());
//商品详情
params.put("detail", dto.getGoodsDesc());
params.put("detail", bo.getGoodsDesc());
//商品类型,不同商品类目的编号见 担保支付商品类目编号
params.put("type", dto.getGoodsType());
params.put("type", bo.getGoodsType());
//订单过期时间,单位秒,300s - 172800s
params.put("expire_time", KSPayConstants.expireTime);
//开发者自定义字段,回调原样回传。超过最大长度会被截断
@ -94,72 +106,65 @@ public class KSPayStrategy extends AbstractPayStrategy{
String sign = ksPayUtil.calcSign(params, secret);
JSONObject payJson = new JSONObject();
payJson.put("out_order_no", dto.getPayId());
payJson.put("out_order_no", bo.getPayId());
payJson.put("open_id", openId);
payJson.put("total_amount", BaseWxPayRequest.yuanToFen(dto.getPayAmount()));
payJson.put("subject", dto.getGoodsSubject());
payJson.put("detail", dto.getGoodsDesc());
payJson.put("type", dto.getGoodsType());
payJson.put("total_amount", BaseWxPayRequest.yuanToFen(bo.getPayAmount()));
payJson.put("subject", bo.getGoodsSubject());
payJson.put("detail", bo.getGoodsDesc());
payJson.put("type", bo.getGoodsType());
payJson.put("expire_time", 1800);
payJson.put("sign", sign);
// payJson.put("attach", "测试支付");
payJson.put("notify_url", dto.getCurrDate());
payJson.put("notify_url", bo.getCurrDate());
log.info("请求参数{}", payJson);
//预下单接口
String ksPayAccessToken = payRestTemplateUtil.ksPostRequestUrlencoded(kspayConfig);
String result = payRestTemplateUtil.ksPostRequestJson(payJson, KSPayConstants.CREATE_ORDER, appId, ksPayAccessToken);
result = payRestTemplateUtil.ksPostRequestJson(payJson, KSPayConstants.CREATE_ORDER, appId, ksPayAccessToken);
log.info("==================================");
log.info("快手预下单result{}", result);
log.info("==================================");
if (!"".equals(result)) {
JSONObject jsonObject = JSONObject.parseObject(result);
String resultCode = jsonObject.getString("result");
if ("1".equals(resultCode)) {
JSONObject data = jsonObject.getJSONObject("order_info");
String orderNo = data.getString("order_no");
String orderToken = data.getString("order_info_token");
if (null != orderToken && null != orderNo) {
//保存预下单信息
PayInOrderVo payInOrderVo = new PayInOrderVo();
//把order_no和order_info_token返回前端用于调起收银台
payInOrderVo.setPayId(dto.getPayId());
payInOrderVo.setPayOrderId(orderNo);
payInOrderVo.setOrderToken(orderToken);
return payInOrderVo;
} else {
log.error("快手支付:统一下单接口调用失败,payId:{},result:{},error{}", dto.getPayId(),JSON.toJSONString(data), "返回信息为空");
throw new ServiceException(ResponseEnum.PAY_FAILS);
}
} else {
log.error("快手支付:统一下单接口调用失败,payId:{},error{}", dto.getPayId(), jsonObject.getString("error_msg"));
throw new ServiceException(ResponseEnum.PAY_FAILS);
}
} else {
log.error("快手支付:统一下单接口调用失败,payId:{},error{}", dto.getPayId(), "请求结果返回为空");
throw new ServiceException(ResponseEnum.PAY_FAILS);
}
} catch (Exception e) {
e.printStackTrace();
log.error("快手支付:支付异常,payId:{},error{}", dto.getPayId(), e.getMessage());
log.error("快手支付:支付异常,payId:{},error{}", bo.getPayId(), e.getMessage());
throw new ServiceException(ResponseEnum.PAY_FAILS);
}
if (StringUtils.isBlank(result)){
log.error("快手支付:统一下单接口调用失败,payId:{},error{}", bo.getPayId(), "请求结果返回为空");
throw new ServiceException(ResponseEnum.PAY_FAILS);
}
JSONObject jsonObject = JSONObject.parseObject(result);
String resultCode = jsonObject.getString("result");
if (!"1".equals(resultCode)) {
log.error("快手支付:统一下单接口调用失败,payId:{},error{}", bo.getPayId(), jsonObject.getString("error_msg"));
throw new ServiceException(ResponseEnum.PAY_FAILS);
}
JSONObject data = jsonObject.getJSONObject("order_info");
String orderNo = data.getString("order_no");
String orderToken = data.getString("order_info_token");
if (StringUtils.isBlank(orderNo) || StringUtils.isBlank(orderToken)) {
log.error("快手支付:统一下单接口调用失败,payId:{},result:{},error{}", bo.getPayId(),JSON.toJSONString(data), "返回信息为空");
throw new ServiceException(ResponseEnum.PAY_FAILS);
}
//保存预下单信息
ThirdInOrderVo thirdInOrderVo = new ThirdInOrderVo();
//把order_no和order_info_token返回前端用于调起收银台
thirdInOrderVo.setOutOrderNo(bo.getPayId());
thirdInOrderVo.setThirdOrderNo(orderNo);
thirdInOrderVo.setOrderToken(orderToken);
return thirdInOrderVo;
}
@Override
public String parsePayNotify(String params) {
List<KspayConfig> kspayConfigList = kspayConfigMapper.selectList(new LambdaQueryWrapper<KspayConfig>().eq(KspayConfig::getStatus, EnumPayConfigStatus.ENABLE.getCode()));
if (CollUtil.isEmpty(kspayConfigList)){
throw new ServiceException(ResponseEnum.PAY_CONFIG_ERROR);
}
KspayConfig kspayConfig = kspayConfigList.get(0);
KspayConfig kspayConfig = getKspayConfig();
String appId = kspayConfig.getAppid();
String secret = kspayConfig.getSecret();
JSONObject jsonObject = JSONObject.parseObject(params);
JSONObject object = jsonObject.getJSONObject("data");
String kwaisign = jsonObject.getString("sign");
String jsonString = JSONObject.toJSONString(object, SerializerFeature.WRITE_MAP_NULL_FEATURES, SerializerFeature.QuoteFieldNames);
log.info("jsonString:" + jsonString);
if (null != kwaisign) {
log.info("快手支付:统一回调处理,params:{}",jsonString);
if (StringUtils.isNotBlank(kwaisign)) {
jsonString = jsonString + secret;
//签名校验
if (kwaisign.equals(DigestUtils.md5Hex(jsonString))) {
@ -183,7 +188,7 @@ public class KSPayStrategy extends AbstractPayStrategy{
//处理业务
PayNotifyCheckDto payNotifyCheckDto = new PayNotifyCheckDto();
payNotifyCheckDto.setPayType(EnumPayType.KS_PAY);
payNotifyCheckDto.setPayAmount(BaseWxPayResult.fenToYuan(orderAmount));
payNotifyCheckDto.setPayAmount(MoneyUtil.fenToYuan(String.valueOf(orderAmount)));
payNotifyCheckDto.setPayId(outOrderNo);
payNotifyCheckDto.setMsg(messageId);
String notifyCheck = super.payNotifyCheck(payNotifyCheckDto);
@ -192,7 +197,7 @@ public class KSPayStrategy extends AbstractPayStrategy{
}
log.info("快手支付回调,交易正常:封装参数修改内部支付单信息");
EditPayInfoNotifyDto editPayInfoNotifyDto = new EditPayInfoNotifyDto();
editPayInfoNotifyDto.setPayAmount(BaseWxPayResult.fenToYuan(orderAmount));
editPayInfoNotifyDto.setPayAmount(MoneyUtil.fenToYuan(String.valueOf(orderAmount)));
editPayInfoNotifyDto.setPayTime(DateUtil.formatDateTime(new Date()));
editPayInfoNotifyDto.setAppId(appId);
editPayInfoNotifyDto.setPayId(outOrderNo);
@ -213,4 +218,73 @@ public class KSPayStrategy extends AbstractPayStrategy{
}
return super.buildNotifyCheckResultMsg(EnumPayType.KS_PAY,true,"business fail");
}
@Override
public ThirdQueryOrderVo queryOrder(QueryOrderBo bo) {
KspayConfig kspayConfig = getKspayConfig();
String appId = kspayConfig.getAppid();
String secret = kspayConfig.getSecret();
String result = "";
try {
//accessToken
String ksPayAccessToken = payRestTemplateUtil.ksPostRequestUrlencoded(kspayConfig);
//加签验签的参数需要排序
Map<String, Object> params = new TreeMap<>();
//小程序APPID
params.put("app_id", appId);
//开发者侧的订单号。需保证同一小程序下不可重复
params.put("out_order_no", bo.getPayId());
//签名
String sign = ksPayUtil.calcSign(params, secret);
JSONObject queryOrderJson = new JSONObject();
queryOrderJson.put("out_order_no", bo.getPayId());
queryOrderJson.put("sign", sign);
//发起请求
result = payRestTemplateUtil.ksPostRequestJson(queryOrderJson, KSPayConstants.QUERY_ORDER, appId, ksPayAccessToken);
}catch (Exception e){
e.printStackTrace();
log.error("快手支付:订单查询异常,payId:{},error{}", bo.getPayId(), e.getMessage());
throw new ServiceException(ResponseEnum.ORDER_QUERY_FAILS);
}
log.info("==================================");
log.info("快手订单查询result{}", result);
log.info("==================================");
if (StringUtils.isBlank(result)) {
log.error("快手支付:订单查询异常,payId:{},error{}", bo.getPayId(), "请求结果返回为空");
throw new ServiceException(ResponseEnum.ORDER_QUERY_FAILS);
}
JSONObject jsonObject = JSONObject.parseObject(result);
String resultCode = jsonObject.getString("result");
if (!"1".equals(resultCode)) {
log.error("快手支付:订单查询异常,payId:{},error{}", bo.getPayId(), jsonObject.getString("error_msg"));
throw new ServiceException(ResponseEnum.ORDER_QUERY_FAILS);
}
JSONObject data = jsonObject.getJSONObject("payment_info");
//开发者下单单号
String outOrderNo = data.getString("out_order_no");
//支付状态。 取值: PROCESSING-处理中|SUCCESS-成功|FAILED-失败 TIMEOUT-超时
String payStatus = data.getString("pay_status");
//预下单用户支付金额
String totalAmount = data.getString("total_amount");
//预下单用户支付金额
String payTime = data.getString("pay_time");
//支付渠道。取值:UNKNOWN - 未知|WECHAT-微信 |ALIPAY-支付宝。(注:如果用户还未支付,这里返回的是UNKNOWN.)
String payChannel = data.getString("pay_channel");
//快手小程序平台订单号
String ksOrderNo = data.getString("ks_order_no");
//开发者回传的订单同步状态
String orderStatus = data.getString("order_status");
//快手小程序平台订单号
String openId = data.getString("open_id");
ThirdQueryOrderVo thirdQueryOrderVo = new ThirdQueryOrderVo();
thirdQueryOrderVo.setOutOrderNo(outOrderNo);
thirdQueryOrderVo.setPayStatus(payStatus);
thirdQueryOrderVo.setTotalAmount(MoneyUtil.fenToYuan(String.valueOf(totalAmount)));
thirdQueryOrderVo.setPayTime(payTime);
thirdQueryOrderVo.setKsPayChannel(payChannel);
thirdQueryOrderVo.setThirdOrderNo(ksOrderNo);
thirdQueryOrderVo.setOrderStatus(orderStatus);
thirdQueryOrderVo.setOpenId(openId);
return thirdQueryOrderVo;
}
}

99
bnyer-services/bnyer-pay/src/main/java/com/bnyer/pay/design/strategy/WxPayStrategy.java

@ -1,46 +1,37 @@
package com.bnyer.pay.design.strategy;
import cn.hutool.core.collection.CollUtil;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.TypeReference;
import com.alipay.api.internal.util.AlipaySignature;
import com.alipay.api.msg.MsgConstants;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.bnyer.common.core.context.SecurityContextHolder;
import com.bnyer.common.core.domain.AlipayConfig;
import com.bnyer.common.core.domain.WxpayConfig;
import com.bnyer.common.core.enums.EnumPayType;
import com.bnyer.common.core.enums.ResponseEnum;
import com.bnyer.common.core.exception.ServiceException;
import com.bnyer.common.core.utils.SpringUtils;
import com.bnyer.common.core.utils.StringUtils;
import com.bnyer.pay.bo.QueryOrderBo;
import com.bnyer.pay.dto.EditPayInfoNotifyDto;
import com.bnyer.pay.dto.PayNotifyCheckDto;
import com.bnyer.pay.dto.UnifiedOrderDto;
import com.bnyer.pay.bo.UnifiedOrderBo;
import com.bnyer.pay.enums.EnumPayChannel;
import com.bnyer.pay.enums.EnumPayConfigStatus;
import com.bnyer.pay.enums.EnumTradeType;
import com.bnyer.pay.manager.WxPayManager;
import com.bnyer.pay.mapper.WxpayConfigMapper;
import com.bnyer.pay.service.PayInfoService;
import com.bnyer.pay.utils.WXPayUtil;
import com.bnyer.pay.vo.PayInOrderVo;
import com.bnyer.pay.vo.ThirdInOrderVo;
import com.bnyer.pay.vo.ThirdQueryOrderVo;
import com.github.binarywang.wxpay.bean.notify.WxPayNotifyResponse;
import com.github.binarywang.wxpay.bean.notify.WxPayOrderNotifyResult;
import com.github.binarywang.wxpay.bean.request.BaseWxPayRequest;
import com.github.binarywang.wxpay.bean.request.WxPayOrderQueryRequest;
import com.github.binarywang.wxpay.bean.request.WxPayUnifiedOrderRequest;
import com.github.binarywang.wxpay.bean.result.BaseWxPayResult;
import com.github.binarywang.wxpay.bean.result.WxPayOrderQueryResult;
import com.github.binarywang.wxpay.bean.result.WxPayUnifiedOrderResult;
import com.github.binarywang.wxpay.constant.WxPayConstants;
import com.github.binarywang.wxpay.exception.WxPayException;
import com.github.binarywang.wxpay.service.WxPayService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.transaction.interceptor.TransactionAspectSupport;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
@ -59,57 +50,57 @@ public class WxPayStrategy extends AbstractPayStrategy {
private PayInfoService payInfoService;
@Override
public PayInOrderVo unifiedOrder(UnifiedOrderDto dto) {
log.info("微信支付:统一下单接口调用开始,WxPayStrategy.unifiedOrder dto:{}",JSON.toJSONString(dto));
PayInOrderVo payInOrderVo = null;
EnumTradeType payByTradeType = EnumTradeType.getPayByTradeType(dto.getTradeType());
public ThirdInOrderVo unifiedOrder(UnifiedOrderBo bo) {
log.info("微信支付:统一下单接口调用开始,WxPayStrategy.unifiedOrder bo:{}",JSON.toJSONString(bo));
ThirdInOrderVo thirdInOrderVo = null;
EnumTradeType payByTradeType = EnumTradeType.getPayByTradeType(bo.getTradeType());
switch (payByTradeType){
case JSAPI_MINI:
payInOrderVo = jsApiPay(dto);
thirdInOrderVo = jsApiPay(bo);
break;
case JSAPI_PUBLIC:
break;
default:
throw new ServiceException("TradeType未匹配上对应支付方式");
}
return payInOrderVo;
return thirdInOrderVo;
}
/**
* JSAPI支付
* @param dto
* @param bo
* @return
*/
private PayInOrderVo jsApiPay(UnifiedOrderDto dto) {
WxpayConfig wxPayConfig = wxPayManager.getWxPayConfigByTradeType(dto.getTradeType());
private ThirdInOrderVo jsApiPay(UnifiedOrderBo bo) {
WxpayConfig wxPayConfig = wxPayManager.getWxPayConfigByTradeType(bo.getTradeType());
WxPayService wxPayService = wxPayManager.getWxPayService(wxPayConfig);
String openId = SecurityContextHolder.getWechatOpenId();
try {
WxPayUnifiedOrderRequest orderRequest = new WxPayUnifiedOrderRequest();
orderRequest.setOpenid(openId);
orderRequest.setOutTradeNo(dto.getPayId());
orderRequest.setBody(dto.getGoodsDesc());
orderRequest.setSpbillCreateIp(dto.getIp());
orderRequest.setTotalFee(BaseWxPayRequest.yuanToFen(dto.getPayAmount()));
orderRequest.setOutTradeNo(bo.getPayId());
orderRequest.setBody(bo.getGoodsDesc());
orderRequest.setSpbillCreateIp(bo.getIp());
orderRequest.setTotalFee(BaseWxPayRequest.yuanToFen(bo.getPayAmount()));
//调用微信支付接口
WxPayUnifiedOrderResult wxPayUnifiedOrderResult = wxPayService.unifiedOrder(orderRequest);
String timestamp = String.valueOf(dto.getCurrDate().getTime());
String timestamp = String.valueOf(bo.getCurrDate().getTime());
if (timestamp.length() > 10) {
timestamp = timestamp.substring(0, 10);
}
//返回数据
PayInOrderVo payInOrderVo = new PayInOrderVo();
payInOrderVo.setPayId(dto.getPayId());
payInOrderVo.setAppid(wxPayConfig.getAppid());
payInOrderVo.setMchid(wxPayConfig.getMchid());
payInOrderVo.setPrepayid(wxPayUnifiedOrderResult.getPrepayId());
payInOrderVo.setNoncestr(wxPayUnifiedOrderResult.getNonceStr());
payInOrderVo.setTimestamp(timestamp);
payInOrderVo.setSign(wxPayUnifiedOrderResult.getSign());
payInOrderVo.setTradeType(wxPayUnifiedOrderResult.getTradeType());
return payInOrderVo;
ThirdInOrderVo thirdInOrderVo = new ThirdInOrderVo();
thirdInOrderVo.setOutOrderNo(bo.getPayId());
thirdInOrderVo.setAppid(wxPayConfig.getAppid());
thirdInOrderVo.setMchid(wxPayConfig.getMchid());
thirdInOrderVo.setPrepayid(wxPayUnifiedOrderResult.getPrepayId());
thirdInOrderVo.setNoncestr(wxPayUnifiedOrderResult.getNonceStr());
thirdInOrderVo.setTimestamp(timestamp);
thirdInOrderVo.setSign(wxPayUnifiedOrderResult.getSign());
thirdInOrderVo.setTradeType(wxPayUnifiedOrderResult.getTradeType());
return thirdInOrderVo;
} catch (WxPayException e) {
log.error("微信支付:统一下单接口调用失败,payId:{},error{}", dto.getPayId(), e.getMessage());
log.error("微信支付:统一下单接口调用失败,payId:{},error{}", bo.getPayId(), e.getMessage());
throw new ServiceException(ResponseEnum.PAY_FAILS);
}
}
@ -171,4 +162,32 @@ public class WxPayStrategy extends AbstractPayStrategy {
return super.buildNotifyCheckResultMsg(EnumPayType.WX_PAY,false,e.getMessage());
}
}
@Override
public ThirdQueryOrderVo queryOrder(QueryOrderBo bo) {
if (StringUtils.isBlank(bo.getTradeType())){
throw new ServiceException("tradeType is null");
}
WxpayConfig wxPayConfig = wxPayManager.getWxPayConfigByTradeType(bo.getTradeType());
WxPayService wxPayService = wxPayManager.getWxPayService(wxPayConfig);
try {
WxPayOrderQueryRequest wxPayOrderQueryRequest = new WxPayOrderQueryRequest();
wxPayOrderQueryRequest.setOutTradeNo(bo.getPayId());
WxPayOrderQueryResult wxPayOrderQueryResult = wxPayService.queryOrder(wxPayOrderQueryRequest);
log.info("==================================");
log.info("微信订单查询result{}", JSON.toJSONString(wxPayOrderQueryResult));
log.info("==================================");
ThirdQueryOrderVo thirdQueryOrderVo = new ThirdQueryOrderVo();
thirdQueryOrderVo.setOutOrderNo(wxPayOrderQueryResult.getOutTradeNo());
thirdQueryOrderVo.setPayStatus(wxPayOrderQueryResult.getTradeState());
thirdQueryOrderVo.setOpenId(wxPayOrderQueryResult.getOpenid());
//处理时间
thirdQueryOrderVo.setPayTime(wxPayOrderQueryResult.getTimeEnd());
thirdQueryOrderVo.setThirdOrderNo(wxPayOrderQueryResult.getTransactionId());
return thirdQueryOrderVo;
} catch (WxPayException e) {
log.error("微信支付:订单查询异常,payId:{},error{}", bo.getPayId(),e.getMessage());
throw new ServiceException(ResponseEnum.ORDER_QUERY_FAILS);
}
}
}

72
bnyer-services/bnyer-pay/src/main/java/com/bnyer/pay/dto/AddPayInfoDto.java

@ -1,39 +1,87 @@
package com.bnyer.pay.dto;
import com.bnyer.common.core.annotation.CustomParamsValidation;
import com.baomidou.mybatisplus.annotation.TableField;
import io.swagger.annotations.ApiModelProperty;
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
import javax.validation.constraints.NotBlank;
import java.math.BigDecimal;
import java.util.Date;
/**
* @author :WXC
* @Date :2023/04/03
* @Date :2023/05/05
* @description :
*/
@Getter
@Setter
@NoArgsConstructor
@AllArgsConstructor
public class AddPayInfoDto {
@NotBlank(message = "业务主订单号不能为空")
@ApiModelProperty(value="业务主订单号:关联内部业务订单表",required = true)
@ApiModelProperty(value="支付单号(内部生成)")
private String payId;
@ApiModelProperty(value="业务主订单号:关联内部业务订单表")
private String orderNo;
@NotBlank(message = "支付场景不能为空")
@ApiModelProperty(value="支付场景:1.会员充值",required = true)
private Integer sceneCode;
@ApiModelProperty(value="支付状态:1000未支付;1001支付成功 ;1002支付失败")
private Integer payStatus;
@ApiModelProperty(value="单笔对账状态:1001 对账成功")
private Integer singleStatus;
@NotBlank(message = "支付类型不能为空")
@ApiModelProperty(value="支付类型:wxpay/alipay",required = true)
@ApiModelProperty(value="单笔对账时间")
private Date singleTime;
@ApiModelProperty(value="支付类型:wxpay/alipay/kspay/dypay")
private String payType;
@ApiModelProperty(value="交易类型 1--JSAPI支付(小程序appId支付)、2--Native支付、3--app支付,4--JSAPI支付(公众号appId支付)5--H5支付,微信支付必填",example = "1")
@CustomParamsValidation(range = "1",message = "交易类型暂时只支持JSAPI")
@ApiModelProperty(value="支付渠道:wxpay/alipay")
private String payChannel;
@ApiModelProperty(value = "交易类型:JSAPI等")
private String tradeType;
@ApiModelProperty(value="支付单号(第三方返回)")
private String payNo;
@ApiModelProperty(value="用户侧订单号(第三方返回)")
private String tradeNo;
@ApiModelProperty(value="appid")
private String appid;
@ApiModelProperty(value="商品标题")
private String goodsSubject;
@ApiModelProperty(value="商品描述")
private String goodsDesc;
@ApiModelProperty(value="支付金额,单位元")
private BigDecimal payAmount;
@ApiModelProperty(value="支付时间")
private Date payTime;
@ApiModelProperty(value="支付场景:1.会员充值")
private Integer sceneCode;
@ApiModelProperty(value="用户ip")
private String ip;
@ApiModelProperty(value="调用第三方下单返回")
private String thirdCode;
@ApiModelProperty(value="调用第三方下单返回")
private String thirdMsg;
@ApiModelProperty(value="调用第三方下单返回")
private String thirdNo;
@ApiModelProperty(value="备注")
private String remark;
}

39
bnyer-services/bnyer-pay/src/main/java/com/bnyer/pay/dto/InOrderDto.java

@ -0,0 +1,39 @@
package com.bnyer.pay.dto;
import com.bnyer.common.core.annotation.CustomParamsValidation;
import io.swagger.annotations.ApiModelProperty;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
import javax.validation.constraints.NotBlank;
/**
* @author :WXC
* @Date :2023/04/03
* @description :
*/
@Getter
@Setter
@NoArgsConstructor
public class InOrderDto {
@NotBlank(message = "业务主订单号不能为空")
@ApiModelProperty(value="业务主订单号:关联内部业务订单表",required = true)
private String orderNo;
@NotBlank(message = "支付场景不能为空")
@ApiModelProperty(value="支付场景:1.会员充值",required = true)
private Integer sceneCode;
@NotBlank(message = "支付类型不能为空")
@ApiModelProperty(value="支付类型:wxpay/alipay",required = true)
private String payType;
@ApiModelProperty(value="交易类型 1--JSAPI支付(小程序appId支付)、2--Native支付、3--app支付,4--JSAPI支付(公众号appId支付)5--H5支付,微信支付必填",example = "1")
@CustomParamsValidation(range = "1",message = "交易类型暂时只支持JSAPI")
private String tradeType;
@ApiModelProperty(value="备注")
private String remark;
}

33
bnyer-services/bnyer-pay/src/main/java/com/bnyer/pay/dto/QueryOrderDto.java

@ -0,0 +1,33 @@
package com.bnyer.pay.dto;
import com.bnyer.common.core.annotation.CustomParamsValidation;
import io.swagger.annotations.ApiModelProperty;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
import javax.validation.constraints.NotBlank;
/**
* @author :WXC
* @Date :2023/05/05
* @description :
*/
@Getter
@Setter
@NoArgsConstructor
public class QueryOrderDto {
@NotBlank(message = "支付类型不能为空")
@ApiModelProperty(value="支付类型:wxpay/alipay/kspay/dypay",required = true)
private String payType;
@ApiModelProperty(value="交易类型 1--JSAPI支付(小程序appId支付)、2--Native支付、3--app支付,4--JSAPI支付(公众号appId支付)5--H5支付,微信支付必填",example = "1")
@CustomParamsValidation(range = "1",message = "交易类型暂时只支持JSAPI")
private String tradeType;
@NotBlank(message = "支付单号不能为空")
@ApiModelProperty(value="支付单号",required = true)
private String payId;
}

37
bnyer-services/bnyer-pay/src/main/java/com/bnyer/pay/enums/EnumDyPayStatus.java

@ -0,0 +1,37 @@
package com.bnyer.pay.enums;
import com.bnyer.common.core.enums.EnumPayStatus;
import com.bnyer.common.core.exception.ServiceException;
import lombok.AllArgsConstructor;
import lombok.Getter;
import java.util.Objects;
/**
* @author :WXC
* @Date :2023/05/05
* @description :
*/
@Getter
@AllArgsConstructor
public enum EnumDyPayStatus {
PROCESSING("PROCESSING",EnumPayStatus.NO_PAY),
SUCCESS("SUCCESS",EnumPayStatus.SUCCESS),
FAIL("FAIL",EnumPayStatus.FAILS),
TIMEOUT("TIMEOUT",EnumPayStatus.FAILS),
;
private final String status;
private final EnumPayStatus enumPayStatus;
public static EnumPayStatus getEnumPayStatusByStatus(String status) {
for (EnumDyPayStatus s : EnumDyPayStatus.values()) {
if (Objects.equals(status, s.getStatus())) {
return s.getEnumPayStatus();
}
}
throw new ServiceException("status 未匹配上对应的支付状态");
}
}

37
bnyer-services/bnyer-pay/src/main/java/com/bnyer/pay/enums/EnumKsPayStatus.java

@ -0,0 +1,37 @@
package com.bnyer.pay.enums;
import com.bnyer.common.core.enums.EnumPayStatus;
import com.bnyer.common.core.exception.ServiceException;
import lombok.AllArgsConstructor;
import lombok.Getter;
import java.util.Objects;
/**
* @author :WXC
* @Date :2023/05/05
* @description :
*/
@Getter
@AllArgsConstructor
public enum EnumKsPayStatus {
PROCESSING("PROCESSING",EnumPayStatus.NO_PAY),
SUCCESS("SUCCESS",EnumPayStatus.SUCCESS),
FAILED("FAILED",EnumPayStatus.FAILS),
TIMEOUT("TIMEOUT",EnumPayStatus.FAILS),
;
private final String status;
private final EnumPayStatus enumPayStatus;
public static EnumPayStatus getEnumPayStatusByStatus(String status) {
for (EnumKsPayStatus s : EnumKsPayStatus.values()) {
if (Objects.equals(status, s.getStatus())) {
return s.getEnumPayStatus();
}
}
throw new ServiceException("status 未匹配上对应的支付状态");
}
}

37
bnyer-services/bnyer-pay/src/main/java/com/bnyer/pay/enums/EnumWxPayStatus.java

@ -0,0 +1,37 @@
package com.bnyer.pay.enums;
import com.bnyer.common.core.enums.EnumPayStatus;
import com.bnyer.common.core.exception.ServiceException;
import lombok.AllArgsConstructor;
import lombok.Getter;
import java.util.Objects;
/**
* @author :WXC
* @Date :2023/05/05
* @description :
*/
@Getter
@AllArgsConstructor
public enum EnumWxPayStatus {
NOT_PAY("NOTPAY",EnumPayStatus.NO_PAY),
USER_PAYING("USERPAYING",EnumPayStatus.NO_PAY),
SUCCESS("SUCCESS",EnumPayStatus.SUCCESS),
PAY_ERROR("PAYERROR",EnumPayStatus.FAILS),
;
private final String status;
private final EnumPayStatus enumPayStatus;
public static EnumPayStatus getEnumPayStatusByStatus(String status) {
for (EnumWxPayStatus s : EnumWxPayStatus.values()) {
if (Objects.equals(status, s.getStatus())) {
return s.getEnumPayStatus();
}
}
throw new ServiceException("status 未匹配上对应的支付状态");
}
}

15
bnyer-services/bnyer-pay/src/main/java/com/bnyer/pay/service/PayInfoService.java

@ -4,9 +4,7 @@ import com.bnyer.common.core.domain.PayInfo;
import com.baomidou.mybatisplus.extension.service.IService;
import com.bnyer.pay.dto.AddPayInfoDto;
import com.bnyer.pay.dto.EditPayInfoNotifyDto;
import com.bnyer.pay.vo.PayInOrderVo;
import javax.servlet.http.HttpServletRequest;
import com.bnyer.pay.vo.PayInfoDetailsVo;
/**
* @author :WXC
@ -14,12 +12,11 @@ import javax.servlet.http.HttpServletRequest;
*/
public interface PayInfoService extends IService<PayInfo>{
/**
* 生成支付订单
* 添加支付订单
* @param dto
* @param request
* @return
*/
PayInOrderVo addPayInOrder(AddPayInfoDto dto, HttpServletRequest request);
void addPayInfo(AddPayInfoDto dto);
/**
* 修改支付单并发消息到订单系统修改订单状态
@ -27,4 +24,10 @@ public interface PayInfoService extends IService<PayInfo>{
*/
void editPayInfoNotify(EditPayInfoNotifyDto editPayInfoNotifyDto);
/**
* 查询订单详情
* @param payId
* @return
*/
PayInfoDetailsVo queryOrder(String payId);
}

31
bnyer-services/bnyer-pay/src/main/java/com/bnyer/pay/service/UnifiedPayService.java

@ -0,0 +1,31 @@
package com.bnyer.pay.service;
import com.bnyer.pay.dto.InOrderDto;
import com.bnyer.pay.dto.QueryOrderDto;
import com.bnyer.pay.vo.QueryOrderVo;
import com.bnyer.pay.vo.ThirdInOrderVo;
import javax.servlet.http.HttpServletRequest;
/**
* @author :WXC
* @Date :2023/05/05
* @description :
*/
public interface UnifiedPayService {
/**
* 统一下单并生成支付订单
* @param dto
* @param request
* @return
*/
ThirdInOrderVo inOrder(InOrderDto dto, HttpServletRequest request);
/**
* 统一订单查询
* @param dto
* @return
*/
QueryOrderVo queryOrder(QueryOrderDto dto);
}

127
bnyer-services/bnyer-pay/src/main/java/com/bnyer/pay/service/impl/PayInfoServiceImpl.java

@ -5,28 +5,17 @@ import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.bnyer.common.core.domain.PayInfo;
import com.bnyer.common.core.domain.R;
import com.bnyer.common.core.enums.EnumSceneCode;
import com.bnyer.common.core.enums.EnumUserClientType;
import com.bnyer.common.core.enums.ResponseEnum;
import com.bnyer.common.core.exception.ServiceException;
import com.bnyer.common.core.utils.OrderUtil;
import com.bnyer.common.core.utils.bean.EntityConvertUtil;
import com.bnyer.common.core.utils.ip.IpUtils;
import com.bnyer.common.rocketmq.config.RocketMqConstant;
import com.bnyer.order.api.dto.QueryVipOrderDto;
import com.bnyer.order.api.remote.RemoteVipOrderService;
import com.bnyer.order.api.vo.VipOrderVo;
import com.bnyer.pay.constant.KSPayConstants;
import com.bnyer.pay.design.factory.PayFactory;
import com.bnyer.pay.design.strategy.IPayStrategy;
import com.bnyer.pay.dto.AddPayInfoDto;
import com.bnyer.pay.dto.EditPayInfoNotifyDto;
import com.bnyer.pay.dto.EditPayInfoSingleDto;
import com.bnyer.pay.dto.UnifiedOrderDto;
import com.bnyer.pay.mapper.PayInfoMapper;
import com.bnyer.pay.service.PayInfoService;
import com.bnyer.pay.vo.PayInOrderVo;
import com.bnyer.pay.vo.PayInfoDetailsVo;
import lombok.extern.slf4j.Slf4j;
import org.apache.rocketmq.client.producer.SendStatus;
import org.apache.rocketmq.spring.core.RocketMQTemplate;
@ -35,10 +24,7 @@ import org.springframework.messaging.support.GenericMessage;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import javax.servlet.http.HttpServletRequest;
import java.math.BigDecimal;
import java.util.Date;
import java.util.List;
import java.util.Objects;
/**
@ -55,105 +41,17 @@ public class PayInfoServiceImpl extends ServiceImpl<PayInfoMapper, PayInfo> impl
@Autowired
private RocketMQTemplate vipOrderPayNotifyMqTemplate;
@Autowired
private RemoteVipOrderService remoteVipOrderService;
/**
* 统一下单并生成支付订单
* 添加支付订单
* @param dto
* @param request
* @return
*/
@Override
public PayInOrderVo addPayInOrder(AddPayInfoDto dto, HttpServletRequest request) {
//支付金额
String payAmount = "";
//商品类型:快手支付需要
int goodsType;
//payId
String payId;
EnumSceneCode enumSceneCode = EnumSceneCode.getSceneCodeByCode(dto.getSceneCode());
switch (enumSceneCode){
//会员充值场景
case VIP_RECHARGE:
QueryVipOrderDto queryVipOrderDto = new QueryVipOrderDto();
queryVipOrderDto.setOrderNo(dto.getOrderNo());
//查询会员业务订单信息
R<List<VipOrderVo>> vipOrderVoListR = remoteVipOrderService.getVipOrderList(queryVipOrderDto);
if (!vipOrderVoListR.isSuccess()){
throw new ServiceException(vipOrderVoListR.getMsg());
}
VipOrderVo vipOrderVo = vipOrderVoListR.getData().get(0);
payAmount = vipOrderVo.getPayAmount().toString();
goodsType = KSPayConstants.GOODS_TYPE_VIP;
payId = OrderUtil.getOrderNo("RV",new Date(), EnumUserClientType.getCodeByType(vipOrderVo.getUserClientType())
,String.valueOf(vipOrderVo.getUserId()));
break;
default:
throw new ServiceException("sceneCode未匹配上对应支付场景");
}
//构建统一下单请求实体
UnifiedOrderDto unifiedOrderDto = buildUnifiedOrderDto(dto, goodsType,payAmount,payId, request);
//下单,获取第三方返回信息
IPayStrategy payStrategy = PayFactory.getInstance().getConcreteStrategy(dto.getPayType());
if (Objects.isNull(payStrategy)){
throw new ServiceException("暂不支持该支付方式");
}
PayInOrderVo payInOrderVo = payStrategy.unifiedOrder(unifiedOrderDto);
//构建支付订单完成入库
PayInfo payInfo = buildPayInfo(payInOrderVo,unifiedOrderDto,dto);
payInfoMapper.insert(payInfo);
return payInOrderVo;
}
/**
* 构建支付订单
*
* @param payInOrderVo
* @param unifiedOrderDto
* @param dto
* @return
*/
private PayInfo buildPayInfo(PayInOrderVo payInOrderVo, UnifiedOrderDto unifiedOrderDto, AddPayInfoDto dto) {
PayInfo payInfo = new PayInfo();
payInfo.setOrderNo(dto.getOrderNo());
payInfo.setSceneCode(dto.getSceneCode());
payInfo.setRemark(dto.getRemark());
payInfo.setPayType(dto.getPayType());
payInfo.setPayId(unifiedOrderDto.getPayId());
payInfo.setPayAmount(new BigDecimal(unifiedOrderDto.getPayAmount()));
payInfo.setAppid(payInOrderVo.getAppid());
payInfo.setGoodsSubject(unifiedOrderDto.getGoodsSubject());
payInfo.setGoodsDesc(unifiedOrderDto.getGoodsDesc());
payInfo.setThirdNo(payInOrderVo.getPrepayid());
payInfo.setIp(unifiedOrderDto.getIp());
public void addPayInfo(AddPayInfoDto dto) {
PayInfo payInfo = EntityConvertUtil.copy(dto, PayInfo.class);
payInfo.setCreateTime(new Date());
payInfo.setIsShow("1");
return payInfo;
}
/**
* 构建统一下单请求实体
*
* @param dto 入参
* @param goodsType
* @param payAmount 不同支付场景下的支付金额
* @param payId 内部系统支付单号
* @param request 请求request用于获取ip地址
* @return
*/
private UnifiedOrderDto buildUnifiedOrderDto(AddPayInfoDto dto, int goodsType, String payAmount, String payId, HttpServletRequest request) {
//当前时间
Date currDate = new Date();
//ip地址
String ip = IpUtils.getIpAddr(request);
UnifiedOrderDto unifiedOrderDto = EntityConvertUtil.copy(dto, UnifiedOrderDto.class);
unifiedOrderDto.setPayId(payId);
unifiedOrderDto.setIp(ip);
unifiedOrderDto.setCurrDate(currDate);
unifiedOrderDto.setPayAmount(payAmount);
unifiedOrderDto.setGoodsType(goodsType);
return unifiedOrderDto;
payInfoMapper.insert(payInfo);
}
/**
@ -222,4 +120,19 @@ public class PayInfoServiceImpl extends ServiceImpl<PayInfoMapper, PayInfo> impl
editPayInfoSingleDto.setPayChannel(editPayInfoSingleDto.getPayChannel());
return editPayInfoSingleDto;
}
/**
* 查询订单详情
* @param payId 支付单号
* @return
*/
@Override
public PayInfoDetailsVo queryOrder(String payId) {
PayInfo payInfo = payInfoMapper.selectOne(new LambdaQueryWrapper<PayInfo>().eq(PayInfo::getPayId, payId));
if (Objects.isNull(payInfo)){
throw new ServiceException(ResponseEnum.NOT_EXIST,"支付订单");
}
PayInfoDetailsVo payInfoDetailsVo = EntityConvertUtil.copy(payInfo, PayInfoDetailsVo.class);
return payInfoDetailsVo;
}
}

209
bnyer-services/bnyer-pay/src/main/java/com/bnyer/pay/service/impl/UnifiedPayServiceImpl.java

@ -0,0 +1,209 @@
package com.bnyer.pay.service.impl;
import com.bnyer.common.core.domain.R;
import com.bnyer.common.core.enums.EnumPayStatus;
import com.bnyer.common.core.enums.EnumPayType;
import com.bnyer.common.core.enums.EnumSceneCode;
import com.bnyer.common.core.enums.EnumUserClientType;
import com.bnyer.common.core.exception.ServiceException;
import com.bnyer.common.core.utils.OrderUtil;
import com.bnyer.common.core.utils.bean.EntityConvertUtil;
import com.bnyer.common.core.utils.ip.IpUtils;
import com.bnyer.order.api.dto.QueryVipOrderDto;
import com.bnyer.order.api.remote.RemoteVipOrderService;
import com.bnyer.order.api.vo.VipOrderVo;
import com.bnyer.pay.bo.QueryOrderBo;
import com.bnyer.pay.bo.UnifiedOrderBo;
import com.bnyer.pay.constant.KSPayConstants;
import com.bnyer.pay.design.factory.PayFactory;
import com.bnyer.pay.design.strategy.IPayStrategy;
import com.bnyer.pay.dto.AddPayInfoDto;
import com.bnyer.pay.dto.InOrderDto;
import com.bnyer.pay.dto.QueryOrderDto;
import com.bnyer.pay.enums.EnumDyPayStatus;
import com.bnyer.pay.enums.EnumKsPayStatus;
import com.bnyer.pay.enums.EnumWxPayStatus;
import com.bnyer.pay.service.PayInfoService;
import com.bnyer.pay.service.UnifiedPayService;
import com.bnyer.pay.vo.QueryOrderVo;
import com.bnyer.pay.vo.ThirdInOrderVo;
import com.bnyer.pay.vo.PayInfoDetailsVo;
import com.bnyer.pay.vo.ThirdQueryOrderVo;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import javax.servlet.http.HttpServletRequest;
import java.math.BigDecimal;
import java.util.Date;
import java.util.List;
import java.util.Objects;
/**
* @author :WXC
* @Date :2023/05/05
* @description :
*/
@Slf4j
@Service
public class UnifiedPayServiceImpl implements UnifiedPayService {
@Autowired
private PayInfoService payInfoService;
@Autowired
private RemoteVipOrderService remoteVipOrderService;
/**
* 统一下单并生成支付订单
* @param dto
* @param request
* @return
*/
@Override
public ThirdInOrderVo inOrder(InOrderDto dto, HttpServletRequest request) {
//支付金额
String payAmount = "";
//商品类型:快手支付需要
int goodsType;
//payId
String payId;
EnumSceneCode enumSceneCode = EnumSceneCode.getSceneCodeByCode(dto.getSceneCode());
switch (enumSceneCode){
//会员充值场景
case VIP_RECHARGE:
QueryVipOrderDto queryVipOrderDto = new QueryVipOrderDto();
queryVipOrderDto.setOrderNo(dto.getOrderNo());
//查询会员业务订单信息
R<List<VipOrderVo>> vipOrderVoListR = remoteVipOrderService.getVipOrderList(queryVipOrderDto);
if (!vipOrderVoListR.isSuccess()){
throw new ServiceException(vipOrderVoListR.getMsg());
}
VipOrderVo vipOrderVo = vipOrderVoListR.getData().get(0);
payAmount = vipOrderVo.getPayAmount().toString();
goodsType = KSPayConstants.GOODS_TYPE_VIP;
payId = OrderUtil.getOrderNo("RV",new Date(), EnumUserClientType.getCodeByType(vipOrderVo.getUserClientType())
,String.valueOf(vipOrderVo.getUserId()));
break;
default:
throw new ServiceException("sceneCode未匹配上对应支付场景");
}
//构建统一下单请求实体
UnifiedOrderBo unifiedOrderBo = buildUnifiedOrderDto(dto, goodsType,payAmount,payId, request);
//下单,获取第三方返回信息
IPayStrategy payStrategy = PayFactory.getInstance().getConcreteStrategy(dto.getPayType());
if (Objects.isNull(payStrategy)){
throw new ServiceException("暂不支持该支付方式");
}
ThirdInOrderVo thirdInOrderVo = payStrategy.unifiedOrder(unifiedOrderBo);
//构建支付订单完成入库
AddPayInfoDto addPayInfoDto = buildPayInfo(thirdInOrderVo, unifiedOrderBo,dto);
payInfoService.addPayInfo(addPayInfoDto);
return thirdInOrderVo;
}
/**
* 构建支付订单
*
* @param thirdInOrderVo
* @param unifiedOrderBo
* @param dto
* @return
*/
private AddPayInfoDto buildPayInfo(ThirdInOrderVo thirdInOrderVo, UnifiedOrderBo unifiedOrderBo, InOrderDto dto) {
AddPayInfoDto addPayInfoDto = new AddPayInfoDto();
addPayInfoDto.setOrderNo(dto.getOrderNo());
addPayInfoDto.setSceneCode(dto.getSceneCode());
addPayInfoDto.setRemark(dto.getRemark());
addPayInfoDto.setPayType(dto.getPayType());
addPayInfoDto.setPayId(unifiedOrderBo.getPayId());
addPayInfoDto.setPayAmount(new BigDecimal(unifiedOrderBo.getPayAmount()));
addPayInfoDto.setAppid(thirdInOrderVo.getAppid());
addPayInfoDto.setGoodsSubject(unifiedOrderBo.getGoodsSubject());
addPayInfoDto.setGoodsDesc(unifiedOrderBo.getGoodsDesc());
addPayInfoDto.setThirdNo(thirdInOrderVo.getPrepayid());
addPayInfoDto.setIp(unifiedOrderBo.getIp());
return addPayInfoDto;
}
/**
* 构建统一下单请求实体
*
* @param dto 入参
* @param goodsType 商品类型
* @param payAmount 不同支付场景下的支付金额
* @param payId 内部系统支付单号
* @param request 请求request用于获取ip地址
* @return
*/
private UnifiedOrderBo buildUnifiedOrderDto(InOrderDto dto, int goodsType, String payAmount, String payId, HttpServletRequest request) {
//当前时间
Date currDate = new Date();
//ip地址
String ip = IpUtils.getIpAddr(request);
UnifiedOrderBo unifiedOrderBo = EntityConvertUtil.copy(dto, UnifiedOrderBo.class);
unifiedOrderBo.setPayId(payId);
unifiedOrderBo.setIp(ip);
unifiedOrderBo.setCurrDate(currDate);
unifiedOrderBo.setPayAmount(payAmount);
unifiedOrderBo.setGoodsType(goodsType);
return unifiedOrderBo;
}
/**
* 统一订单查询
* @param dto
* @return
*/
@Override
public QueryOrderVo queryOrder(QueryOrderDto dto) {
//先查询系统支付单是否已经完成支付,如果因为延迟导致没有及时同步,在调用第三方接口查询支付状态返回
PayInfoDetailsVo payInfoDetailsVo = payInfoService.queryOrder(dto.getPayId());
Integer payStatus = payInfoDetailsVo.getPayStatus();
EnumPayStatus enumPayStatus = EnumPayStatus.getEnumPayStatusByStatus(payStatus);
if (EnumPayStatus.NO_PAY != enumPayStatus){
QueryOrderVo queryOrderVo = new QueryOrderVo();
queryOrderVo.setPayId(dto.getPayId());
queryOrderVo.setPayStatus(enumPayStatus.getStatus());
return queryOrderVo;
}
//获取第三方订单信息
IPayStrategy strategy = PayFactory.getInstance().getConcreteStrategy(dto.getPayType());
if (Objects.isNull(strategy)){
throw new ServiceException("暂不支持该支付方式");
}
//构建统一订单查询实体
QueryOrderBo queryOrderBo = EntityConvertUtil.copy(dto, QueryOrderBo.class);
ThirdQueryOrderVo thirdQueryOrderVo = strategy.queryOrder(queryOrderBo);
QueryOrderVo queryOrderVo = new QueryOrderVo();
queryOrderVo.setPayId(dto.getPayId());
queryOrderVo.setPayStatus(getPayStatus(dto.getPayType(), thirdQueryOrderVo.getPayStatus()));
return queryOrderVo;
}
/**
* 通过第三方系统支付状态构建业务系统对应支付状态
* @param payType
* @param thirdPayStatus
* @return
*/
private Integer getPayStatus(String payType,String thirdPayStatus){
EnumPayType enumPayType = EnumPayType.getEnumPayTypeByType(payType);
switch (enumPayType){
case KS_PAY:
EnumPayStatus enumPayStatusKs = EnumKsPayStatus.getEnumPayStatusByStatus(thirdPayStatus);
return enumPayStatusKs.getStatus();
case WX_PAY:
EnumPayStatus enumPayStatusWx = EnumWxPayStatus.getEnumPayStatusByStatus(thirdPayStatus);
return enumPayStatusWx.getStatus();
case DY_PAY:
EnumPayStatus enumPayStatusDy = EnumDyPayStatus.getEnumPayStatusByStatus(thirdPayStatus);
return enumPayStatusDy.getStatus();
case ALI_PAY:
default:
throw new ServiceException("payType 参数参数传递错误");
}
}
}

131
bnyer-services/bnyer-pay/src/main/java/com/bnyer/pay/utils/MoneyUtil.java

@ -0,0 +1,131 @@
package com.bnyer.pay.utils;
import org.apache.commons.lang3.StringUtils;
import java.math.BigDecimal;
import java.text.DecimalFormat;
public class MoneyUtil {
/**
* 费用元TO元
* 四舍五入保留2位小数
* 正常情况用不到但是如果传入的不合规范的超长小数点则需要规范小数例如12.26999999999998
* @param yuan
* @return
*/
public static String yuanToYuan(String yuan){
return yuanToYuan(yuan,false);
}
/**
* 费用元TO元
* 四舍五入保留2位小数
* 正常情况用不到但是如果传入的不合规范的超长小数点则需要规范小数例如12.26999999999998
* @param yuan
* @param returnZeroFlag
* @return
*/
public static String yuanToYuan(String yuan,boolean returnZeroFlag){
String ret = "0";
if(StringUtils.isNotBlank(yuan)){
try{
DecimalFormat df = new DecimalFormat("0.00");
ret = df.format(Float.valueOf(yuan));
}catch(Exception e){}
}else{
if(returnZeroFlag) {//空的时候是否返回0
return ret;
}else{
return yuan;
}
}
return ret;
}
/**
* 费用元TO分
* @return
*/
public static String yuanToFen(String yuan){
return yuanToFen(yuan,false);
}
/**
*
* @param yuan
* @param returnZeroFlag 入参空的是或否是否返回0
* @return
*/
public static String yuanToFen(String yuan,boolean returnZeroFlag){
String ret = "0";
if(StringUtils.isNotBlank(yuan)){
try{
BigDecimal res = new BigDecimal(yuan).multiply(new BigDecimal(100));
DecimalFormat df = new DecimalFormat("0");
ret = df.format(res.doubleValue());
}catch(Exception e){}
}else{
if(returnZeroFlag) {//空的时候是否返回0
return ret;
}else{
return yuan;
}
}
return ret;
}
/**
* 费用分TO元
* 格式化0.00 表示比如结果0.50
* #.00表示比如.50
* @param fen
* @return
*/
public static String fenToYuan(String fen){
return fenToYuan(fen,false);
}
/**
* 费用分TO元
* 格式化0.00 表示比如结果0.50
* #.00表示比如.50
* @param fen
* @param returnZeroFlag
* @return
*/
public static String fenToYuan(String fen,boolean returnZeroFlag){
String ret = "0.00";
if(StringUtils.isNotBlank(fen)){
try{
BigDecimal res = new BigDecimal(fen).divide(new BigDecimal(100));
DecimalFormat df = new DecimalFormat("0.00");
ret = df.format(res.doubleValue());
}catch(Exception e){}
}else{
if(returnZeroFlag){//空的时候是否返回0
return ret;
}else{
return fen;
}
}
return ret;
}
public static void main(String[] args) {
String[] yuans = new String[]{
"1.01","12.09","123.08","1234.11","12345.99","123456.11","1234567.98","12345678.02","123456789.01","1234567890.55","12345678901.99"
};
for(String yuan : yuans){
String fen = yuanToFen(yuan);
System.out.println(yuan+"元转分"+fen);
System.out.println(fen+"分转元"+fenToYuan(fen));
}
}
}

19
bnyer-services/bnyer-pay/src/main/java/com/bnyer/pay/vo/PayInfoDetailsVo.java

@ -0,0 +1,19 @@
package com.bnyer.pay.vo;
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
/**
* @author :WXC
* @Date :2023/05/05
* @description :
*/
@Getter
@Setter
@NoArgsConstructor
@AllArgsConstructor
public class PayInfoDetailsVo extends PayInfoVo {
}

86
bnyer-services/bnyer-pay/src/main/java/com/bnyer/pay/vo/PayInfoVo.java

@ -0,0 +1,86 @@
package com.bnyer.pay.vo;
import io.swagger.annotations.ApiModelProperty;
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
import java.math.BigDecimal;
import java.util.Date;
/**
* @author :WXC
* @Date :2023/05/05
* @description :
*/
@Getter
@Setter
@NoArgsConstructor
@AllArgsConstructor
public class PayInfoVo {
@ApiModelProperty(value="支付单号(内部生成)")
private String payId;
@ApiModelProperty(value="业务主订单号:关联内部业务订单表")
private String orderNo;
@ApiModelProperty(value="支付状态:1000未支付;1001支付成功 ;1002支付失败")
private Integer payStatus;
@ApiModelProperty(value="单笔对账状态:1001 对账成功")
private Integer singleStatus;
@ApiModelProperty(value="单笔对账时间")
private Date singleTime;
@ApiModelProperty(value="支付类型:wxpay/alipay/kspay/dypay")
private String payType;
@ApiModelProperty(value="支付渠道:wxpay/alipay")
private String payChannel;
@ApiModelProperty(value = "交易类型:JSAPI等")
private String tradeType;
@ApiModelProperty(value="支付单号(第三方返回)")
private String payNo;
@ApiModelProperty(value="用户侧订单号(第三方返回)")
private String tradeNo;
@ApiModelProperty(value="appid")
private String appid;
@ApiModelProperty(value="商品标题")
private String goodsSubject;
@ApiModelProperty(value="商品描述")
private String goodsDesc;
@ApiModelProperty(value="支付金额,单位元")
private BigDecimal payAmount;
@ApiModelProperty(value="支付时间")
private Date payTime;
@ApiModelProperty(value="支付场景:1.会员充值")
private Integer sceneCode;
@ApiModelProperty(value="用户ip")
private String ip;
@ApiModelProperty(value="调用第三方下单返回")
private String thirdCode;
@ApiModelProperty(value="调用第三方下单返回")
private String thirdMsg;
@ApiModelProperty(value="调用第三方下单返回")
private String thirdNo;
@ApiModelProperty(value="备注")
private String remark;
}

22
bnyer-services/bnyer-pay/src/main/java/com/bnyer/pay/vo/QueryOrderVo.java

@ -0,0 +1,22 @@
package com.bnyer.pay.vo;
import io.swagger.annotations.ApiModelProperty;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
/**
* @author :WXC
* @Date :2023/05/05
* @description :
*/
@Getter
@Setter
@NoArgsConstructor
public class QueryOrderVo {
@ApiModelProperty(value="内部支付单号")
private String payId;
@ApiModelProperty(value = "支付状态:1000未支付;1001支付成功 ;1002支付失败")
private Integer payStatus;
}

8
bnyer-services/bnyer-pay/src/main/java/com/bnyer/pay/vo/PayInOrderVo.java → bnyer-services/bnyer-pay/src/main/java/com/bnyer/pay/vo/ThirdInOrderVo.java

@ -13,7 +13,7 @@ import lombok.Setter;
@Getter
@Setter
@NoArgsConstructor
public class PayInOrderVo {
public class ThirdInOrderVo {
@ApiModelProperty(value = "appid")
private String appid;
@ -39,11 +39,11 @@ public class PayInOrderVo {
@ApiModelProperty(value = "支付宝")
private String outStr;
@ApiModelProperty(value = "内部系统支付单号")
private String payId;
@ApiModelProperty(value = "内部系统支付单号/开发者测单号")
private String outOrderNo;
@ApiModelProperty(value = "第三方返回支付单号,抖音快手支付需要用到")
private String payOrderId;
private String thirdOrderNo;
@ApiModelProperty(value = "快手、抖音支付")
private String orderToken;

42
bnyer-services/bnyer-pay/src/main/java/com/bnyer/pay/vo/ThirdQueryOrderVo.java

@ -0,0 +1,42 @@
package com.bnyer.pay.vo;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
/**
* @author :WXC
* @Date :2023/05/05
* @description :
*/
@Getter
@Setter
@NoArgsConstructor
public class ThirdQueryOrderVo {
//开发者下单单号
private String outOrderNo;
/**
* 快手取值PROCESSING-处理中SUCCESS-成功FAILED-失败 TIMEOUT-超时
* 抖音取值SUCCESS成功 TIMEOUT超时未支付 PROCESSING处理中 FAIL失败
* 微信取值SUCCESS支付成功,REFUND转入退款,NOTPAY未支付,CLOSED已关闭,REVOKED已撤销刷卡支付,USERPAYING--用户支付中,PAYERROR--支付失败(其他原因如银行返回失败)
* 支付宝取值
*/
private String payStatus;
//预下单用户支付金额:单位统一成元
private String totalAmount;
//订单支付时间,统一处理为yyyy-MM-dd HH:mm:ss
private String payTime;
//快手支付渠道。取值:UNKNOWN - 未知|WECHAT-微信 |ALIPAY-支付宝。(注:如果用户还未支付,这里返回的是UNKNOWN.)
private String ksPayChannel;
//抖音支付渠道
private Integer dyPayChannel;
//第三方平台订单号:抖音快手平台订单号
private String thirdOrderNo;
//开发者回传的订单同步状态
private String orderStatus;
//订单对应的用户openid
private String openId;
//支付渠道侧的支付单号
private String channelNo;
}

4
bnyer-services/bnyer-pay/src/main/resources/com/bnyer/pay/mapper/PayInfoMapper.xml

@ -6,7 +6,7 @@
<!--@Table pay_pay_info-->
<id column="id" jdbcType="BIGINT" property="id" />
<result column="pay_id" jdbcType="VARCHAR" property="payId" />
<result column="order_id" jdbcType="VARCHAR" property="orderId" />
<result column="order_id" jdbcType="VARCHAR" property="orderNo" />
<result column="pay_status" jdbcType="INTEGER" property="payStatus" />
<result column="single_status" jdbcType="INTEGER" property="singleStatus" />
<result column="single_time" jdbcType="TIMESTAMP" property="singleTime" />
@ -52,7 +52,7 @@
<if test="payChannel != null and payChannel != ''">
set pay_channel = #{payChannel},
</if>
set order_status = 1001,
set pay_status = 1001,
set single_status = 1003,
set single_time = now()
where pay_id = #{payId}

Loading…
Cancel
Save