This commit is contained in:
77
2024-11-25 18:09:52 +08:00
parent ab685878b7
commit fa1d6df347
16 changed files with 542 additions and 111 deletions

View File

@@ -0,0 +1,95 @@
package com.ruoyi.cai.controller;
import cn.dev33.satoken.annotation.SaCheckPermission;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.ruoyi.cai.domain.PayTrdConfig;
import com.ruoyi.cai.service.PayTrdConfigService;
import com.ruoyi.common.annotation.Log;
import com.ruoyi.common.annotation.RepeatSubmit;
import com.ruoyi.common.core.controller.BaseController;
import com.ruoyi.common.core.domain.PageQuery;
import com.ruoyi.common.core.domain.R;
import com.ruoyi.common.core.page.TableDataInfo;
import com.ruoyi.common.core.validate.AddGroup;
import com.ruoyi.common.core.validate.EditGroup;
import com.ruoyi.common.enums.BusinessType;
import lombok.RequiredArgsConstructor;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import javax.validation.constraints.NotEmpty;
import javax.validation.constraints.NotNull;
import java.util.Arrays;
/**
* 四方支付配置
*
* @author ruoyi
* @date 2024-11-25
*/
@Validated
@RequiredArgsConstructor
@RestController
@RequestMapping("/cai/payTrdConfig")
public class PayTrdConfigController extends BaseController {
private final PayTrdConfigService payTrdConfigService;
/**
* 查询四方支付配置列表
*/
@SaCheckPermission("cai:payTrdConfig:list")
@GetMapping("/list")
public TableDataInfo<PayTrdConfig> list(PayTrdConfig bo, PageQuery pageQuery) {
Page<PayTrdConfig> page = payTrdConfigService.page(pageQuery.build(), Wrappers.lambdaQuery(bo));
return TableDataInfo.build(page);
}
/**
* 获取四方支付配置详细信息
*
* @param id 主键
*/
@SaCheckPermission("cai:payTrdConfig:query")
@GetMapping("/{id}")
public R<PayTrdConfig> getInfo(@NotNull(message = "主键不能为空")
@PathVariable Long id) {
return R.ok(payTrdConfigService.getById(id));
}
/**
* 新增四方支付配置
*/
@SaCheckPermission("cai:payTrdConfig:add")
@Log(title = "四方支付配置", businessType = BusinessType.INSERT)
@RepeatSubmit()
@PostMapping()
public R<Void> add(@Validated(AddGroup.class) @RequestBody PayTrdConfig bo) {
return toAjax(payTrdConfigService.save(bo));
}
/**
* 修改四方支付配置
*/
@SaCheckPermission("cai:payTrdConfig:edit")
@Log(title = "四方支付配置", businessType = BusinessType.UPDATE)
@RepeatSubmit()
@PutMapping()
public R<Void> edit(@Validated(EditGroup.class) @RequestBody PayTrdConfig bo) {
return toAjax(payTrdConfigService.updateById(bo));
}
/**
* 删除四方支付配置
*
* @param ids 主键串
*/
@SaCheckPermission("cai:payTrdConfig:remove")
@Log(title = "四方支付配置", businessType = BusinessType.DELETE)
@DeleteMapping("/{ids}")
public R<Void> remove(@NotEmpty(message = "主键不能为空")
@PathVariable Long[] ids) {
return toAjax(payTrdConfigService.removeBatchByIds(Arrays.asList(ids)));
}
}

View File

@@ -0,0 +1,62 @@
package com.ruoyi.cai.domain;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Data;
import java.io.Serializable;
import java.time.LocalDateTime;
/**
* 四方支付配置对象 cai_pay_trd_config
*
* @author ruoyi
* @date 2024-11-25
*/
@Data
@TableName("cai_pay_trd_config")
public class PayTrdConfig implements Serializable {
private static final long serialVersionUID=1L;
/**
*
*/
@TableId(value = "id")
private Long id;
/**
* 第三方支付类型
*/
private String type;
/**
* 第三方支付名称
*/
private String name;
/**
* 请求域名
*/
private String gatewayUrl;
/**
* 回调域名
*/
private String notifyUrl;
/**
* 商户ID
*/
private String mchId;
/**
* 秘钥
*/
private String sign;
private String aliProductId;
private Integer enableStatus;
/**
* 是否删除
*/
private Integer deleteFlag;
private LocalDateTime createTime;
}

View File

@@ -0,0 +1,14 @@
package com.ruoyi.cai.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.ruoyi.cai.domain.PayTrdConfig;
/**
* 四方支付配置Mapper接口
*
* @author ruoyi
* @date 2024-11-25
*/
public interface PayTrdConfigMapper extends BaseMapper<PayTrdConfig> {
}

View File

@@ -182,6 +182,8 @@ public class PayManager {
dto.setSubject(vipOrder.getVipName());
dto.setPrice(vipOrder.getPrice());
dto.setOrderNo(vipOrder.getOrderNo());
dto.setAppid(vipOrder.getAppid());
dto.setPlatformType(vipOrder.getPlatformType());
break;
case RECHARGE_ORDER_SUB:
RechargeOrder rechargeOrder = rechargeOrderService.getByOrderNo(orderNo);
@@ -196,6 +198,8 @@ public class PayManager {
dto.setSubject(rechargeOrder.getRechargeName());
dto.setPrice(rechargeOrder.getPrice());
dto.setOrderNo(rechargeOrder.getOrderNo());
dto.setAppid(rechargeOrder.getAppid());
dto.setPlatformType(rechargeOrder.getPlatformType());
break;
default:
break;

View File

@@ -11,6 +11,8 @@ public class PayOrderInfoDTO {
private String subject;
private BigDecimal price;
private String orderNo;
private String appid;
private String platformType;
public String getPriceFenStr(){
return NumberUtil.mul(price,100).longValue()+"";

View File

@@ -1,5 +1,8 @@
package com.ruoyi.cai.pay;
import lombok.Getter;
@Getter
public enum PayTypeEnum {
ALI(1),
WX(2),
@@ -11,7 +14,4 @@ public enum PayTypeEnum {
this.code = code;
}
public Integer getCode() {
return code;
}
}

View File

@@ -0,0 +1,20 @@
package com.ruoyi.cai.service;
import com.alibaba.fastjson2.JSONObject;
import com.baomidou.mybatisplus.extension.service.IService;
import com.ruoyi.cai.domain.PayTrdConfig;
import com.ruoyi.cai.pay.PayOrderInfoDTO;
/**
* 四方支付配置Service接口
*
* @author ruoyi
* @date 2024-11-25
*/
public interface PayTrdConfigService extends IService<PayTrdConfig> {
String createOrderAli(PayOrderInfoDTO dto);
JSONObject queryOrder(String orderNo, String trdPayType);
JSONObject resetOrder(String orderNo, String trdPayType);
}

View File

@@ -0,0 +1,155 @@
package com.ruoyi.cai.service.impl;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson2.JSONObject;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.ruoyi.cai.domain.PayTrdConfig;
import com.ruoyi.cai.mapper.PayTrdConfigMapper;
import com.ruoyi.cai.pay.PayManager;
import com.ruoyi.cai.pay.PayOrderInfoDTO;
import com.ruoyi.cai.pay.PayTypeEnum;
import com.ruoyi.cai.service.PayTrdConfigService;
import com.ruoyi.cai.trdpay.TrdPayManager;
import com.ruoyi.cai.trdpay.TrdPayTypeEnum;
import com.ruoyi.common.exception.ServiceException;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.HashMap;
import java.util.Map;
/**
* 四方支付配置Service业务层处理
*
* @author ruoyi
* @date 2024-11-25
*/
@Service
@Slf4j
public class PayTrdConfigServiceImpl extends ServiceImpl<PayTrdConfigMapper, PayTrdConfig> implements PayTrdConfigService {
@Autowired
private TrdPayManager trdPayManager;
@Autowired
private PayManager payManager;
@Override
public String createOrderAli(PayOrderInfoDTO dto){
PayTrdConfig payTrdConfig = getEnableStatus();
if(payTrdConfig == null){
throw new ServiceException("未开启支付,请联系客服");
}
TrdPayTypeEnum typeEnum = TrdPayTypeEnum.getByCode(payTrdConfig.getType());
if(typeEnum == null){
throw new ServiceException("未开启支付,请联系客服");
}
JSONObject jsonObject = trdPayManager.createOrderAli(dto, payTrdConfig, typeEnum);
if(jsonObject == null){
log.error("第三方支付失败 返回数据为空");
throw new ServiceException("调用支付失败");
}
if(typeEnum == TrdPayTypeEnum.V1){ // V1
if(!"SUCCESS".equals(jsonObject.getString("retCode"))){
log.info("第三方支付失败 V1统一支付失败失败 dto={}, payTrdConfig={}, typeEnum={}", JSON.toJSONString(dto), JSON.toJSONString(payTrdConfig),JSON.toJSONString(typeEnum));
throw new ServiceException("调用支付失败");
}
return jsonObject.getJSONObject("payParams").getString("payUrl");
}else if(typeEnum == TrdPayTypeEnum.V2){
if(!"0".equals(jsonObject.getString("retCode"))){
log.info("第三方支付失败 V2统一支付失败失败 dto={}, payTrdConfig={}, typeEnum={}", JSON.toJSONString(dto), JSON.toJSONString(payTrdConfig),JSON.toJSONString(typeEnum));
throw new ServiceException("调用支付失败");
}
return JSON.toJSONString(jsonObject);
}
return null;
}
private PayTrdConfig getEnableStatus(){
return this.getOne(Wrappers.lambdaQuery(PayTrdConfig.class).eq(PayTrdConfig::getEnableStatus, 1)
.eq(PayTrdConfig::getDeleteFlag, 0).last("limit 1"));
}
private PayTrdConfig getConfigByPay(String type){
PayTrdConfig one = this.getOne(Wrappers.lambdaQuery(PayTrdConfig.class).eq(PayTrdConfig::getEnableStatus, 1)
.eq(PayTrdConfig::getType, type).eq(PayTrdConfig::getDeleteFlag, 0).last("limit 1"));
if(one != null){
return one;
}
one = this.getOne(Wrappers.lambdaQuery(PayTrdConfig.class)
.eq(PayTrdConfig::getType, type).eq(PayTrdConfig::getDeleteFlag, 0).last("limit 1"));
if(one != null){
return one;
}
one = this.getOne(Wrappers.lambdaQuery(PayTrdConfig.class)
.eq(PayTrdConfig::getType, type).last("limit 1"));
return one;
}
@Override
public JSONObject queryOrder(String orderNo, String trdPayType){
TrdPayTypeEnum typeEnum = TrdPayTypeEnum.getByCode(trdPayType);
PayTrdConfig payTrdConfig = getConfigByPay(trdPayType);
if(typeEnum == null || payTrdConfig == null){
throw new ServiceException("配置数据为空");
}
return trdPayManager.queryOrder(orderNo,payTrdConfig,typeEnum);
}
@Override
public JSONObject resetOrder(String orderNo, String trdPayType){
// PayOrderInfoDTO orderInfo = payManager.getOrderInfo(orderNo);
// if(orderInfo == null){
// throw new ServiceException("订单不存在");
// }
// if(!PayTypeEnum.TRD.getCode().toString().equals(orderInfo.getPlatformType())){
// throw new ServiceException("订单不属于第三方支付");
// }
// String appid = orderInfo.getAppid();
TrdPayTypeEnum typeEnum = TrdPayTypeEnum.getByCode(trdPayType);
PayTrdConfig payTrdConfig = getConfigByPay(trdPayType);
if(typeEnum == null || payTrdConfig == null){
throw new ServiceException("配置数据为空");
}
JSONObject jsonObject = trdPayManager.queryOrder(orderNo,payTrdConfig,typeEnum);
if(typeEnum == TrdPayTypeEnum.V1){ // V1
if(!"SUCCESS".equals(jsonObject.getString("retCode"))){
log.info("第三方支付失败 V1统一支付失败失败 orderNo={}, payTrdConfig={}, typeEnum={}", orderNo, JSON.toJSONString(payTrdConfig),JSON.toJSONString(typeEnum));
throw new ServiceException("调用支付失败");
}
Integer status = jsonObject.getInteger("status");
if(status != null && status.equals(2)){
String mchOrderNo = jsonObject.getString("mchOrderNo");
String payOrderId = jsonObject.getString("payOrderId");
String productId = jsonObject.getString("productId");
Map<String,String> objectJson = new HashMap<>();
for (String key : jsonObject.keySet()) {
objectJson.put(key, jsonObject.getString(key));
}
payManager.callBack(mchOrderNo,payOrderId,objectJson,productId, PayTypeEnum.TRD);
}
return jsonObject;
}else if(typeEnum == TrdPayTypeEnum.V2){
if(!"0".equals(jsonObject.getString("retCode"))){
log.info("第三方支付失败 V2统一支付失败失败 orderNo={}, payTrdConfig={}, typeEnum={}", orderNo, JSON.toJSONString(payTrdConfig),JSON.toJSONString(typeEnum));
throw new ServiceException("调用支付失败");
}
Integer status = jsonObject.getInteger("status");
if(status != null && (status.equals(2) || status.equals(3))){
String mchOrderNo = jsonObject.getString("mchOrderNo");
String payOrderId = jsonObject.getString("payOrderId");
String productId = jsonObject.getString("productId");
Map<String,String> objectJson = new HashMap<>();
for (String key : jsonObject.keySet()) {
objectJson.put(key, jsonObject.getString(key));
}
payManager.callBack(mchOrderNo,payOrderId,objectJson,productId, PayTypeEnum.TRD);
}
return jsonObject;
}
return jsonObject;
}
}

View File

@@ -5,13 +5,13 @@ import cn.hutool.crypto.digest.DigestUtil;
import com.alibaba.fastjson2.JSON;
import com.alibaba.fastjson2.JSONObject;
import com.ruoyi.cai.domain.Account;
import com.ruoyi.cai.domain.PayTrdConfig;
import com.ruoyi.cai.enums.SystemConfigEnum;
import com.ruoyi.cai.manager.SystemConfigManager;
import com.ruoyi.cai.pay.PayManager;
import com.ruoyi.cai.pay.PayOrderInfoDTO;
import com.ruoyi.cai.pay.PayTypeEnum;
import com.ruoyi.cai.service.AccountService;
import com.ruoyi.common.exception.ServiceException;
import com.ruoyi.common.utils.ServletUtils;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
@@ -24,6 +24,8 @@ import org.springframework.web.client.RestTemplate;
import java.math.BigDecimal;
import java.nio.charset.StandardCharsets;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
@@ -34,14 +36,6 @@ import java.util.stream.Collectors;
@Slf4j
public class TrdPayManager {
private final String CREATE_ORDER_URL = "http://pay.jpay.one/api/pay/create_order";
private final String QUERY_ORDER_URL = "http://pay.jpay.one/api/pay/query_order";
private static final String NOTIFY_ALI_URL = "/api/pay/trd/notify";
@Autowired
private TrdPayProperties trdPayProperties;
public static RestTemplate restTemplate;
static {
@@ -59,12 +53,37 @@ public class TrdPayManager {
}
}
public JSONObject createOrderWx(PayOrderInfoDTO payOrderInfoDTO){
return createOrder(payOrderInfoDTO,trdPayProperties.getWxProductId());
}
public JSONObject createOrderAli(PayOrderInfoDTO payOrderInfoDTO){
return createOrder(payOrderInfoDTO,trdPayProperties.getAliProductId());
public JSONObject createOrderAli(PayOrderInfoDTO payOrderInfoDTO, PayTrdConfig payTrdConfig,TrdPayTypeEnum typeEnum){
Map<String, String> params = new HashMap<>();
params.put("mchId", payTrdConfig.getMchId());
params.put("productId", payTrdConfig.getAliProductId());
params.put("mchOrderNo", payOrderInfoDTO.getOrderNo());
params.put("amount", payOrderInfoDTO.getPriceFenStr());
if(typeEnum == TrdPayTypeEnum.V2){
params.put("reqTime", LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyyMMddHHmmss")));
params.put("version","1.0");
params.put("clientIp", ServletUtils.getClientIP());
params.put("subject",payOrderInfoDTO.getSubject());
params.put("body",payOrderInfoDTO.getBody());
params.put("currency","cny");
}
String notifyUrl = payTrdConfig.getNotifyUrl() + typeEnum.getNotifyPath();
params.put("notifyUrl", notifyUrl);
String para = createParams(params,payTrdConfig.getSign());
String gatewayUrl = typeEnum.getGatewayUrl();
if(StringUtils.isNotBlank(payTrdConfig.getGatewayUrl())){
gatewayUrl = payTrdConfig.getGatewayUrl();
}
String createOrderUrl = gatewayUrl + typeEnum.getCreateOrderUrl();
String url = createOrderUrl + "?" + para;
String body = restTemplate.getForEntity(url, String.class).getBody();
JSONObject jsonObject = JSON.parseObject(body);
if(jsonObject == null){
log.error("第三方支付失败 返回数据为空");
throw new ServiceException("调用支付失败");
}
log.info("第三方支付成功 URL={}, body={}",url, body);
return jsonObject;
}
@Autowired
@@ -87,76 +106,35 @@ public class TrdPayManager {
return true;
}
@Autowired
private PayManager payManager;
public JSONObject resetOrder(String orderNo){
JSONObject jsonObject = queryOrder(orderNo);
Integer status = jsonObject.getInteger("status");
if(status != null && status.equals(2)){
String mchOrderNo = jsonObject.getString("mchOrderNo");
String payOrderId = jsonObject.getString("payOrderId");
String productId = jsonObject.getString("productId");
Map<String,String> objectJson = new HashMap<>();
for (String key : jsonObject.keySet()) {
objectJson.put(key, jsonObject.getString(key));
}
payManager.callBack(mchOrderNo,payOrderId,objectJson,productId, PayTypeEnum.TRD);
}
return jsonObject;
}
public JSONObject queryOrder(String orderNo){
public JSONObject queryOrder(String orderNo, PayTrdConfig payTrdConfig,TrdPayTypeEnum typeEnum){
Map<String, String> params = new HashMap<>();
params.put("mchId", trdPayProperties.getMchId());
params.put("mchId", payTrdConfig.getMchId());
params.put("mchOrderNo", orderNo);
String para = createParams(params);
String url = QUERY_ORDER_URL + "?" + para;
String para = createParams(params,payTrdConfig.getSign());
String gatewayUrl = typeEnum.getGatewayUrl();
if(StringUtils.isNotBlank(payTrdConfig.getGatewayUrl())){
gatewayUrl = payTrdConfig.getGatewayUrl();
}
String queryOrderUrl = gatewayUrl + typeEnum.getQueryOrderUrl();
String url = queryOrderUrl + "?" + para;
String body = restTemplate.getForEntity(url, String.class).getBody();
JSONObject jsonObject = JSON.parseObject(body);
if(jsonObject == null){
log.error("第三方支付查询失败 返回数据为空");
throw new ServiceException("调用支付失败");
}
if(!"SUCCESS".equals(jsonObject.getString("retCode"))){
log.info("第三方支付查询失败 第三方支付查询失败 url={}, body={}",url, body);
throw new ServiceException("调用支付失败");
}
log.info("第三方支付成功 URL={}, body={}",url, body);
return jsonObject;
}
public JSONObject createOrder(PayOrderInfoDTO payOrderInfoDTO,String productId){
Map<String, String> params = new HashMap<>();
params.put("mchId", trdPayProperties.getMchId());
params.put("productId", productId);
params.put("mchOrderNo", payOrderInfoDTO.getOrderNo());
params.put("amount", payOrderInfoDTO.getPriceFenStr());
String notifyUrl = trdPayProperties.getNotifyUrlDomain() + NOTIFY_ALI_URL;
params.put("notifyUrl", notifyUrl);
String para = createParams(params);
String url = CREATE_ORDER_URL + "?" + para;
String body = restTemplate.getForEntity(url, String.class).getBody();
JSONObject jsonObject = JSON.parseObject(body);
if(jsonObject == null){
log.error("第三方支付失败 返回数据为空");
throw new ServiceException("调用支付失败");
}
if(!"SUCCESS".equals(jsonObject.getString("retCode"))){
log.info("第三方支付失败 统一支付失败失败 url={}, body={}",url, body);
throw new ServiceException("调用支付失败");
}
log.info("第三方支付成功 URL={}, body={}",url, body);
return jsonObject;
}
private String createParams(Map<String, String> params){
private String createParams(Map<String, String> params,String key){
List<String> url = new ArrayList<>();
for (Map.Entry<String, String> entry : params.entrySet()) {
url.add(entry.getKey()+"="+entry.getValue());
}
url = url.stream().sorted().collect(Collectors.toList());
String stringSignTemp = StringUtils.join(url, "&") + "&key=" + trdPayProperties.getSignKey();
String stringSignTemp = StringUtils.join(url, "&") + "&key=" + key;
String sign = DigestUtil.md5Hex(stringSignTemp).toUpperCase();
url.add("sign="+sign);
return StringUtils.join(url, "&");
@@ -164,16 +142,6 @@ public class TrdPayManager {
public static void main(String[] args) {
TrdPayProperties payProperties = new TrdPayProperties();
payProperties.setMchId("10418");
payProperties.setNotifyUrlDomain("https://api.ssss.com");
PayOrderInfoDTO payOrderInfo = new PayOrderInfoDTO();
payOrderInfo.setPrice(new BigDecimal("10"));
payOrderInfo.setOrderNo("DSKsdasklddshjkasdka");
TrdPayManager trdPayManager = new TrdPayManager();
// trdPayManager.(payProperties);
trdPayManager.createOrder(payOrderInfo,"8000");
}

View File

@@ -0,0 +1,33 @@
package com.ruoyi.cai.trdpay;
import com.ruoyi.cai.pay.PayTypeEnum;
import lombok.Getter;
@Getter
public enum TrdPayTypeEnum {
V1("http://pay.jpay.one/api","/pay/create_order","/pay/query_order","/api/pay/trd/notify/v1"),
V2("http://121.40.24.67:56700/api","/pay/create_order","/pay/query_order","/api/pay/trd/notify/v2"),
;
private final String gatewayUrl;
private final String createOrderUrl;
private final String queryOrderUrl;
private final String notifyPath;
TrdPayTypeEnum(String gatewayUrl, String createOrderUrl, String queryOrderUrl, String notifyPath) {
this.gatewayUrl = gatewayUrl;
this.createOrderUrl = createOrderUrl;
this.queryOrderUrl = queryOrderUrl;
this.notifyPath = notifyPath;
}
public static TrdPayTypeEnum getByCode(String type) {
TrdPayTypeEnum[] values = TrdPayTypeEnum.values();
for (TrdPayTypeEnum value : values) {
if(value.name().equals(type)){
return value;
}
}
return null;
}
}

View File

@@ -0,0 +1,20 @@
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.ruoyi.cai.mapper.PayTrdConfigMapper">
<resultMap type="com.ruoyi.cai.domain.PayTrdConfig" id="PayTrdConfigResult">
<result property="id" column="id"/>
<result property="type" column="type"/>
<result property="name" column="name"/>
<result property="gatewayUrl" column="gateway_url"/>
<result property="notifyUrl" column="notify_url"/>
<result property="mchId" column="mch_id"/>
<result property="sign" column="sign"/>
<result property="deleteFlag" column="delete_flag"/>
<result property="createTime" column="create_time"/>
</resultMap>
</mapper>