支付修改
This commit is contained in:
parent
309bcb18a2
commit
4c1cf4d042
|
@ -29,12 +29,18 @@
|
|||
<version>4.5.7</version>
|
||||
</dependency>
|
||||
|
||||
<!--支付宝SDK-->
|
||||
<!--支付宝SDK V2-->
|
||||
<dependency>
|
||||
<groupId>com.alipay.sdk</groupId>
|
||||
<artifactId>alipay-sdk-java</artifactId>
|
||||
<version>4.40.0.ALL</version>
|
||||
</dependency>
|
||||
<!--支付宝SDK V3-->
|
||||
<!-- <dependency>-->
|
||||
<!-- <groupId>com.alipay.sdk</groupId>-->
|
||||
<!-- <artifactId>alipay-sdk-java-v3</artifactId>-->
|
||||
<!-- <version>3.1.22.ALL</version>-->
|
||||
<!-- </dependency>-->
|
||||
|
||||
<!--阿里云短信发送start-->
|
||||
<!--这个SDK和支付宝的SDK有冲突-->
|
||||
|
|
|
@ -36,6 +36,9 @@ public class AliConfig {
|
|||
@Value("${ali.aesPrivateKey}")
|
||||
private String aesPrivateKey;
|
||||
|
||||
@Value("${ali.notifyUrl}")
|
||||
private String notifyUrl;
|
||||
|
||||
private AlipayConfig getAlipayConfig() {
|
||||
AlipayConfig alipayConfig = new AlipayConfig();
|
||||
alipayConfig.setServerUrl("https://openapi.alipay.com/gateway.do");
|
||||
|
|
|
@ -0,0 +1,31 @@
|
|||
package com.ruoyi.common.pay;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
/**
|
||||
* @author wjh
|
||||
* 2024/12/10
|
||||
*/
|
||||
public interface PayApi {
|
||||
|
||||
// 发起支付
|
||||
Object pay(Payable payable);
|
||||
|
||||
// 关闭支付单
|
||||
void closeByOutTradeNo(String outTradeNo);
|
||||
|
||||
// 查询支付单
|
||||
Object queryByOutTradeNo(String outTradeNo);
|
||||
|
||||
// 退款
|
||||
Object refund(Refundable refundAble);
|
||||
|
||||
// 是否支付成功
|
||||
boolean isPaySuccessByOutTradeNo(String outTradeNo);
|
||||
|
||||
// 是否支付成功
|
||||
boolean isPaySuccess(Object result);
|
||||
|
||||
// 获取支付成功的时间
|
||||
LocalDateTime getPayTime(Object result);
|
||||
}
|
|
@ -1,6 +1,7 @@
|
|||
package com.ruoyi.common.pay.wx.domain;
|
||||
package com.ruoyi.common.pay;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.math.RoundingMode;
|
||||
|
||||
/**
|
||||
* @author wjh
|
||||
|
@ -11,7 +12,14 @@ public interface Payable {
|
|||
/**
|
||||
* 获取价格(分)
|
||||
*/
|
||||
BigDecimal payableMoney();
|
||||
BigDecimal payableFen();
|
||||
|
||||
/**
|
||||
* 获取价格(元)
|
||||
*/
|
||||
default BigDecimal payableYuan() {
|
||||
return payableFen().divide(BigDecimal.valueOf(100), 2, RoundingMode.HALF_UP);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取描述
|
||||
|
@ -29,7 +37,7 @@ public interface Payable {
|
|||
String payableOutTradeNo();
|
||||
|
||||
/**
|
||||
* 获取微信openId
|
||||
* 获取openId
|
||||
*/
|
||||
String payableOpenId();
|
||||
}
|
|
@ -1,12 +1,15 @@
|
|||
package com.ruoyi.common.pay.wx.domain;
|
||||
package com.ruoyi.common.pay;
|
||||
|
||||
import com.wechat.pay.java.service.refund.model.AmountReq;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.math.RoundingMode;
|
||||
|
||||
/**
|
||||
* @author wjh
|
||||
* 2024/7/10
|
||||
*/
|
||||
public interface RefundAble {
|
||||
public interface Refundable {
|
||||
|
||||
// 原商户订单号
|
||||
String refundOutTradeNo();
|
||||
|
@ -20,4 +23,9 @@ public interface RefundAble {
|
|||
// 退款金额(分)
|
||||
AmountReq refundAmount();
|
||||
|
||||
default BigDecimal refundAmountYuan() {
|
||||
return BigDecimal.valueOf(refundAmount().getRefund())
|
||||
.divide(BigDecimal.valueOf(100), 2, RoundingMode.HALF_UP);
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,23 @@
|
|||
package com.ruoyi.common.pay.ali.enums;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Getter;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
|
||||
/**
|
||||
* @author wjh
|
||||
* 2024/12/10
|
||||
*/
|
||||
@Getter
|
||||
@AllArgsConstructor
|
||||
public enum AliTradeStatusEnum {
|
||||
|
||||
WAIT_BUYER_PAY("WAIT_BUYER_PAY", "交易创建,等待买家付款"),
|
||||
TRADE_CLOSED("TRADE_CLOSED", "未付款交易超时关闭,或支付完成后全额退款"),
|
||||
TRADE_SUCCESS("TRADE_SUCCESS", "交易支付成功"),
|
||||
TRADE_FINISHED("TRADE_FINISHED", "交易结束,不可退款");
|
||||
|
||||
private String status;
|
||||
private String msg;
|
||||
|
||||
}
|
|
@ -0,0 +1,154 @@
|
|||
package com.ruoyi.common.pay.ali.service;
|
||||
|
||||
import cn.hutool.json.JSONObject;
|
||||
import com.alipay.api.AlipayClient;
|
||||
import com.alipay.api.domain.AlipayTradeCreateModel;
|
||||
import com.alipay.api.domain.AlipayTradeQueryModel;
|
||||
import com.alipay.api.domain.AlipayTradeRefundModel;
|
||||
import com.alipay.api.request.AlipayTradeCloseRequest;
|
||||
import com.alipay.api.request.AlipayTradeCreateRequest;
|
||||
import com.alipay.api.request.AlipayTradeQueryRequest;
|
||||
import com.alipay.api.request.AlipayTradeRefundRequest;
|
||||
import com.alipay.api.response.AlipayTradeCloseResponse;
|
||||
import com.alipay.api.response.AlipayTradeCreateResponse;
|
||||
import com.alipay.api.response.AlipayTradeQueryResponse;
|
||||
import com.alipay.api.response.AlipayTradeRefundResponse;
|
||||
import com.ruoyi.common.auth.ali.AliConfig;
|
||||
import com.ruoyi.common.exception.ServiceException;
|
||||
import com.ruoyi.common.pay.PayApi;
|
||||
import com.ruoyi.common.pay.Payable;
|
||||
import com.ruoyi.common.pay.Refundable;
|
||||
import com.ruoyi.common.pay.ali.enums.AliTradeStatusEnum;
|
||||
import com.ruoyi.common.utils.DateUtils;
|
||||
import com.ruoyi.common.utils.ServiceUtil;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
/**
|
||||
* @author wjh
|
||||
* 2024/12/10
|
||||
*/
|
||||
@Service
|
||||
public class AliPayService implements PayApi {
|
||||
|
||||
@Autowired
|
||||
private AlipayClient alipayClient;
|
||||
|
||||
@Autowired
|
||||
private AliConfig aliConfig;
|
||||
|
||||
public String pay(Payable payable) {
|
||||
// 构造请求参数以调用接口
|
||||
AlipayTradeCreateRequest request = new AlipayTradeCreateRequest();
|
||||
AlipayTradeCreateModel data = new AlipayTradeCreateModel();
|
||||
// 设置商户订单号
|
||||
data.setOutTradeNo(payable.payableOutTradeNo());
|
||||
// 设置产品码
|
||||
data.setProductCode("JSAPI_PAY");
|
||||
// 设置小程序appId
|
||||
data.setOpAppId(aliConfig.getAppId());
|
||||
// 设置订单总金额(元)
|
||||
data.setTotalAmount(payable.payableYuan().toString());
|
||||
// 设置订单标题
|
||||
data.setSubject(payable.payableDescription());
|
||||
// 设置订单附加信息
|
||||
data.setBody(payable.payableAttach());
|
||||
// 设置买家支付宝用户唯一标识
|
||||
data.setBuyerOpenId(payable.payableOpenId());
|
||||
request.setBizModel(data);
|
||||
request.setNotifyUrl(aliConfig.getNotifyUrl());
|
||||
|
||||
try {
|
||||
AlipayTradeCreateResponse response = alipayClient.execute(request);
|
||||
ServiceUtil.assertion(!response.isSuccess(), response.getMsg());
|
||||
return response.getTradeNo();
|
||||
} catch (Exception e) {
|
||||
throw new ServiceException("调用支付宝下单失败:" + e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 关闭支付订单
|
||||
*/
|
||||
public void closeByOutTradeNo(String outTradeNo) {
|
||||
AlipayTradeCloseRequest request = new AlipayTradeCloseRequest();
|
||||
JSONObject bizContent = new JSONObject();
|
||||
bizContent.put("out_trade_no", outTradeNo);
|
||||
request.setBizContent(bizContent.toString());
|
||||
try {
|
||||
AlipayTradeCloseResponse response = alipayClient.execute(request);
|
||||
ServiceUtil.assertion(!response.isSuccess(), response.getMsg());
|
||||
} catch (Exception e) {
|
||||
throw new ServiceException("调用支付宝关闭订单失败:" + e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public AlipayTradeQueryResponse queryByOutTradeNo(String outTradeNo) {
|
||||
// 构造请求参数以调用接口
|
||||
AlipayTradeQueryRequest request = new AlipayTradeQueryRequest();
|
||||
AlipayTradeQueryModel model = new AlipayTradeQueryModel();
|
||||
|
||||
// 设置订单支付时传入的商户订单号
|
||||
model.setOutTradeNo(outTradeNo);
|
||||
request.setBizModel(model);
|
||||
|
||||
try {
|
||||
AlipayTradeQueryResponse response = alipayClient.execute(request);
|
||||
ServiceUtil.assertion(!response.isSuccess(), response.getMsg());
|
||||
return response;
|
||||
} catch (Exception e) {
|
||||
throw new ServiceException("调用支付宝查询订单失败:" + e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 发起退款
|
||||
*
|
||||
* @param refund
|
||||
*/
|
||||
public AlipayTradeRefundResponse refund(Refundable refund) {
|
||||
// 构造请求参数以调用接口
|
||||
AlipayTradeRefundRequest request = new AlipayTradeRefundRequest();
|
||||
AlipayTradeRefundModel model = new AlipayTradeRefundModel();
|
||||
|
||||
// 设置商户订单号
|
||||
model.setOutTradeNo(refund.refundOutTradeNo());
|
||||
// 设置退款金额
|
||||
model.setRefundAmount(refund.refundAmountYuan().toString());
|
||||
// 设置退款原因说明
|
||||
model.setRefundReason(refund.refundReason());
|
||||
// 设置退款请求号
|
||||
model.setOutRequestNo(refund.refundOutRefundNo());
|
||||
request.setBizModel(model);
|
||||
|
||||
try {
|
||||
AlipayTradeRefundResponse response = alipayClient.execute(request);
|
||||
ServiceUtil.assertion(!response.isSuccess(), response.getMsg());
|
||||
return response;
|
||||
} catch (Exception e) {
|
||||
throw new ServiceException("调用支付宝退款失败:" + e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isPaySuccessByOutTradeNo(String outTradeNo) {
|
||||
AlipayTradeQueryResponse res = this.queryByOutTradeNo(outTradeNo);
|
||||
return isPaySuccess(res);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isPaySuccess(Object result) {
|
||||
AlipayTradeQueryResponse res = (AlipayTradeQueryResponse) result;
|
||||
return res != null && AliTradeStatusEnum.TRADE_SUCCESS.getStatus().equals(res.getTradeStatus());
|
||||
}
|
||||
|
||||
@Override
|
||||
public LocalDateTime getPayTime(Object result) {
|
||||
AlipayTradeQueryResponse res = (AlipayTradeQueryResponse) result;
|
||||
return DateUtils.toLocalDateTime(res.getSendPayDate());
|
||||
}
|
||||
}
|
|
@ -2,18 +2,20 @@ package com.ruoyi.common.pay.syb.service;
|
|||
|
||||
import com.alibaba.fastjson2.JSON;
|
||||
import com.ruoyi.common.exception.ServiceException;
|
||||
import com.ruoyi.common.pay.PayApi;
|
||||
import com.ruoyi.common.pay.syb.config.SybConfig;
|
||||
import com.ruoyi.common.pay.syb.enums.SybTrxStatus;
|
||||
import com.ruoyi.common.pay.syb.util.SybUtil;
|
||||
import com.ruoyi.common.pay.wx.domain.Payable;
|
||||
import com.ruoyi.common.pay.wx.domain.RefundAble;
|
||||
import com.ruoyi.common.pay.Payable;
|
||||
import com.ruoyi.common.pay.Refundable;
|
||||
import com.ruoyi.common.utils.DateUtils;
|
||||
import com.ruoyi.common.utils.ServiceUtil;
|
||||
import com.ruoyi.common.utils.StringUtils;
|
||||
import com.wechat.pay.java.service.payments.jsapi.model.PrepayWithRequestPaymentResponse;
|
||||
import com.wechat.pay.java.service.payments.model.Transaction;
|
||||
import com.wechat.pay.java.service.refund.model.Refund;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.Map;
|
||||
import java.util.TreeMap;
|
||||
|
||||
|
@ -22,7 +24,7 @@ import java.util.TreeMap;
|
|||
* 2024/9/9
|
||||
*/
|
||||
@Service
|
||||
public class SybPayService {
|
||||
public class SybPayService implements PayApi {
|
||||
|
||||
@Autowired
|
||||
private SybPayClient sybPayClient;
|
||||
|
@ -33,10 +35,10 @@ public class SybPayService {
|
|||
/**
|
||||
* 微信小程序预下单
|
||||
*/
|
||||
public PrepayWithRequestPaymentResponse prepayWxApp(Payable payable) {
|
||||
public PrepayWithRequestPaymentResponse pay(Payable payable) {
|
||||
try {
|
||||
Map<String, String> result = sybPayClient.pay(
|
||||
payable.payableMoney().longValue(),
|
||||
payable.payableFen().longValue(),
|
||||
payable.payableOutTradeNo(),
|
||||
"W06",
|
||||
payable.payableDescription(),
|
||||
|
@ -95,7 +97,7 @@ public class SybPayService {
|
|||
/**
|
||||
* 使用商户自定义订单编号查询支付订单
|
||||
*/
|
||||
public Map<String, String> queryOrderByOutTradeNo(String outTradeNo) {
|
||||
public Map<String, String> queryByOutTradeNo(String outTradeNo) {
|
||||
try {
|
||||
return sybPayClient.query(outTradeNo, "");
|
||||
} catch (Exception e) {
|
||||
|
@ -106,23 +108,43 @@ public class SybPayService {
|
|||
/**
|
||||
* 微信退款
|
||||
*/
|
||||
public Map<String, String> refundWx(RefundAble refundAble) {
|
||||
public Map<String, String> refund(Refundable refundAble) {
|
||||
try {
|
||||
return sybPayClient.refund(
|
||||
refundAble.refundAmount().getRefund().longValue(),
|
||||
Map<String, String> result = sybPayClient.refund(
|
||||
refundAble.refundAmount().getRefund(),
|
||||
refundAble.refundOutRefundNo(),
|
||||
"",
|
||||
refundAble.refundOutTradeNo()
|
||||
);
|
||||
ServiceUtil.assertion(result == null, "退款失败,响应数据为空");
|
||||
String trxStatus = result.get("trxstatus");
|
||||
ServiceUtil.assertion(!SybTrxStatus.isSuccess(trxStatus), "发起退款失败:" + result.get("errmsg"));
|
||||
return result;
|
||||
} catch (Exception e) {
|
||||
throw new ServiceException("发起退款异常:" + e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isPaySuccessByOutTradeNo(String outTradeNo) {
|
||||
return isPaySuccess(this.queryByOutTradeNo(outTradeNo));
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isPaySuccess(Object result) {
|
||||
return SybTrxStatus.isSuccess((Map<String, String>)result);
|
||||
}
|
||||
|
||||
@Override
|
||||
public LocalDateTime getPayTime(Object result) {
|
||||
Map<String, String> res = (Map<String, String>)result;
|
||||
return DateUtils.toLocalDate(res.get("fintime"), "yyyyMMddHHmmss");
|
||||
}
|
||||
|
||||
/**
|
||||
* 关闭微信支付订单
|
||||
*/
|
||||
public void closeOrderWx(String outTradeNo) {
|
||||
public void closeByOutTradeNo(String outTradeNo) {
|
||||
try {
|
||||
sybPayClient.close("", outTradeNo);
|
||||
} catch (Exception e) {
|
||||
|
|
|
@ -1,97 +0,0 @@
|
|||
package com.ruoyi.common.pay.tm;
|
||||
|
||||
import com.alibaba.fastjson2.JSON;
|
||||
import com.ruoyi.common.utils.SnowFlakeUtil;
|
||||
import com.ruoyi.common.utils.http.HttpUtils;
|
||||
import com.ruoyi.common.utils.uuid.IdUtils;
|
||||
|
||||
import java.util.HashMap;
|
||||
|
||||
public class Application {
|
||||
|
||||
private final static String HTTP = "https://pos.weixincore.com";
|
||||
private final static String SIGNKEY = "ac6d97e67b444b7a43edfc9182634786";
|
||||
|
||||
public static void main(String[] args) {
|
||||
orderQuery("tmwx1727172604248");
|
||||
// miniPay();
|
||||
}
|
||||
|
||||
/**
|
||||
* 订单查询
|
||||
*/
|
||||
public static void orderQuery(String outTradeId) {
|
||||
HashMap<String, Object> body = new HashMap<>();
|
||||
body.put("outTradeId", outTradeId);
|
||||
body.put("terminalType", "1");
|
||||
body.put("shopId", "488");
|
||||
doPost("/open/Pay/orderQuery", body);
|
||||
}
|
||||
|
||||
/**
|
||||
* 退款
|
||||
*/
|
||||
public static void refund() {
|
||||
HashMap<String,Object> body = new HashMap<>();
|
||||
body.put("refundFee", "0.01");
|
||||
body.put("terminalType", "1");
|
||||
body.put("tradeId", "1");
|
||||
body.put("shopId", "488");
|
||||
doPost("/open/Pay/refund", body);
|
||||
}
|
||||
|
||||
|
||||
// /**
|
||||
// * jsapi支付
|
||||
// */
|
||||
// public static void pay() {
|
||||
// HashMap<String, String> body = new HashMap<String, String>();
|
||||
// body.put("payAmount", "1");
|
||||
// body.put("terminalType", "1");
|
||||
// body.put("shopId", "488");
|
||||
// // 填充必填字段
|
||||
// body.put("payType", "wx_pay"); // 支付方式,可以是 wx.pay, ali.pay, union.online
|
||||
// body.put("outTradeId", "tradeId123"); // 商户订单号
|
||||
// body.put("body", "商品描述"); // 商品描述
|
||||
// body.put("notifyUrl", "https://yourdomain.com/notify"); // 异步回调URL
|
||||
// body.put("frontUrl", "https://yourdomain.com/front"); // 前端页面跳转URL
|
||||
// doPost("/open/Pay/unifiedOrder", body);
|
||||
// }
|
||||
|
||||
|
||||
/**
|
||||
* 小程序支付
|
||||
*/
|
||||
public static void miniPay() {
|
||||
HashMap<String, Object> body = new HashMap<>();
|
||||
body.put("payAmount", "1");
|
||||
body.put("terminalType", "1");
|
||||
body.put("shopId", "488");
|
||||
// 填充必填字段
|
||||
body.put("payType", "wx_pay"); // 支付方式,可以是 wx.pay, ali.pay, union.online
|
||||
body.put("outTradeId", SnowFlakeUtil.newId()); // 商户订单号
|
||||
System.out.println("----------------------------------:"+body.get("outTradeId"));
|
||||
body.put("openid", "o6yEK7Z0OdWM2N_d8ehItn-5NBH8"); // openid
|
||||
body.put("body", "商品描述"); // 商品描述
|
||||
body.put("notifyUrl", "https://yourdomain.com/notify"); // 异步回调URL
|
||||
body.put("frontUrl", "https://yourdomain.com/front"); // 前端页面跳转URL
|
||||
doPost("/open/Pay/miniPay", body);
|
||||
}
|
||||
|
||||
private static void doPost(String url, HashMap<String, Object> body) {
|
||||
body.put("developerId", "100001");
|
||||
body.put("version", "1.0");
|
||||
body.put("timestamp", String.valueOf(System.currentTimeMillis() / 1000));
|
||||
body.put("nonceStr", TmPayUtil.getRandomString(16));
|
||||
String bodyStr = TmPayUtil.getAsciiSort(body);
|
||||
String sign = TmPayUtil.getMD5Code(bodyStr+"&key="+SIGNKEY).toUpperCase();
|
||||
body.put("sign", sign);
|
||||
|
||||
HashMap<String, String> headerData = new HashMap<String, String>();
|
||||
headerData.put("Content-Type", "application/json");
|
||||
|
||||
String response = HttpUtils.sendPostWithHeaders(HTTP + url, headerData,JSON.toJSONString(body));
|
||||
System.out.println("API Response: " + response);
|
||||
}
|
||||
|
||||
}
|
|
@ -3,16 +3,20 @@ package com.ruoyi.common.pay.tm;
|
|||
import com.alibaba.fastjson2.JSON;
|
||||
import com.alibaba.fastjson2.JSONObject;
|
||||
import com.ruoyi.common.exception.ServiceException;
|
||||
import com.ruoyi.common.pay.PayApi;
|
||||
import com.ruoyi.common.pay.tm.config.TmPayConfig;
|
||||
import com.ruoyi.common.pay.tm.enums.TmPayStatus;
|
||||
import com.ruoyi.common.pay.tm.vo.RefundInfo;
|
||||
import com.ruoyi.common.pay.tm.vo.TmTradeInfo;
|
||||
import com.ruoyi.common.pay.wx.domain.Payable;
|
||||
import com.ruoyi.common.pay.wx.domain.RefundAble;
|
||||
import com.ruoyi.common.pay.Payable;
|
||||
import com.ruoyi.common.pay.Refundable;
|
||||
import com.ruoyi.common.utils.DateUtils;
|
||||
import com.ruoyi.common.utils.http.HttpUtils;
|
||||
import com.wechat.pay.java.service.payments.jsapi.model.PrepayWithRequestPaymentResponse;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
|
@ -20,7 +24,7 @@ import java.util.Map;
|
|||
* 太米支付
|
||||
*/
|
||||
@Service
|
||||
public class TmPayService {
|
||||
public class TmPayService implements PayApi {
|
||||
|
||||
@Autowired
|
||||
private TmPayConfig config;
|
||||
|
@ -28,7 +32,7 @@ public class TmPayService {
|
|||
/**
|
||||
* 订单查询
|
||||
*/
|
||||
public TmTradeInfo orderQuery(String outTradeNo) {
|
||||
public TmTradeInfo queryByOutTradeNo(String outTradeNo) {
|
||||
HashMap<String, Object> body = new HashMap<>();
|
||||
body.put("outTradeId", outTradeNo);
|
||||
body.put("terminalType", "1");
|
||||
|
@ -50,7 +54,7 @@ public class TmPayService {
|
|||
/**
|
||||
* 退款
|
||||
*/
|
||||
public RefundInfo refund(RefundAble refundAble) {
|
||||
public RefundInfo refund(Refundable refundAble) {
|
||||
HashMap<String, Object> body = new HashMap<>();
|
||||
body.put("refundFee", String.valueOf(refundAble.refundAmount().getRefund()));
|
||||
body.put("terminalType", "1");
|
||||
|
@ -61,8 +65,7 @@ public class TmPayService {
|
|||
JSONObject jsonResponse = JSON.parseObject(response);
|
||||
if (jsonResponse.getInteger("errCode") == 0 && "退款成功".equals(jsonResponse.getString("errMsg"))) {
|
||||
JSONObject tradeInfo = jsonResponse.getJSONObject("refundInfo");
|
||||
RefundInfo refundInfo = tradeInfo.toJavaObject(RefundInfo.class);
|
||||
return refundInfo;
|
||||
return tradeInfo.toJavaObject(RefundInfo.class);
|
||||
} else {
|
||||
throw new ServiceException("退款失败: " + jsonResponse.getString("errMsg"));
|
||||
}
|
||||
|
@ -70,23 +73,49 @@ public class TmPayService {
|
|||
throw new ServiceException("退款数据为空");
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isPaySuccessByOutTradeNo(String outTradeNo) {
|
||||
TmTradeInfo result = queryByOutTradeNo(outTradeNo);
|
||||
return isPaySuccess(result);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isPaySuccess(Object result) {
|
||||
TmTradeInfo res = (TmTradeInfo) result;
|
||||
return res != null && TmPayStatus.isSuccess(res.getPayStatus());
|
||||
}
|
||||
|
||||
@Override
|
||||
public LocalDateTime getPayTime(Object result) {
|
||||
TmTradeInfo res = (TmTradeInfo) result;
|
||||
return DateUtils.toLocalDateTime(res.getPayTime(), "yyyy-MM-dd HH:mm:ss");
|
||||
}
|
||||
|
||||
/**
|
||||
* 关闭订单
|
||||
*/
|
||||
public void closeOrder(String outTradeNo) {
|
||||
public void closeByOutTradeNo(String outTradeNo) {
|
||||
HashMap<String, Object> body = new HashMap<>();
|
||||
body.put("outTradeId", outTradeNo);
|
||||
body.put("terminalType", "1");
|
||||
body.put("shopId", config.getShopId());
|
||||
doPost(config.getHttpUrl() + "/open/Pay/orderClose", body, config);
|
||||
String response = doPost(config.getHttpUrl() + "/open/Pay/orderClose", body, config);
|
||||
if (com.ruoyi.common.utils.StringUtils.hasText(response)) {
|
||||
JSONObject jsonResponse = JSON.parseObject(response);
|
||||
if (jsonResponse.getInteger("errCode") != 0) {
|
||||
throw new ServiceException("关闭订单失败: " + jsonResponse.getString("errMsg"));
|
||||
}
|
||||
}else{
|
||||
throw new ServiceException("关闭订单数据为空");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 微信小程序支付
|
||||
*/
|
||||
public PrepayWithRequestPaymentResponse wxPay(Payable payable) {
|
||||
public PrepayWithRequestPaymentResponse pay(Payable payable) {
|
||||
HashMap<String, Object> body = new HashMap<>();
|
||||
body.put("payAmount", String.valueOf(payable.payableMoney()));
|
||||
body.put("payAmount", String.valueOf(payable.payableFen()));
|
||||
body.put("terminalType", "1");
|
||||
body.put("shopId", config.getShopId()); // 从渠道获取shopId
|
||||
body.put("sn", null);
|
||||
|
|
|
@ -1,8 +1,12 @@
|
|||
package com.ruoyi.common.pay.wx.service;
|
||||
|
||||
import com.alibaba.fastjson2.JSON;
|
||||
import com.ruoyi.common.pay.PayApi;
|
||||
import com.ruoyi.common.pay.Payable;
|
||||
import com.ruoyi.common.pay.Refundable;
|
||||
import com.ruoyi.common.pay.wx.config.WxPayConfig;
|
||||
import com.ruoyi.common.pay.wx.domain.*;
|
||||
import com.ruoyi.common.pay.wx.util.WxPayUtil;
|
||||
import com.ruoyi.common.utils.DateUtils;
|
||||
import com.wechat.pay.java.service.payments.jsapi.JsapiService;
|
||||
import com.wechat.pay.java.service.payments.jsapi.JsapiServiceExtension;
|
||||
import com.wechat.pay.java.service.payments.jsapi.model.*;
|
||||
|
@ -15,6 +19,7 @@ import org.springframework.beans.factory.annotation.Autowired;
|
|||
import org.springframework.stereotype.Service;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
/**
|
||||
* 微信支付服务
|
||||
|
@ -23,7 +28,7 @@ import java.math.BigDecimal;
|
|||
*/
|
||||
@Service
|
||||
@Slf4j
|
||||
public class WxPayService {
|
||||
public class WxPayService implements PayApi {
|
||||
|
||||
@Autowired
|
||||
private JsapiService jsapiService;
|
||||
|
@ -39,8 +44,8 @@ public class WxPayService {
|
|||
|
||||
private static final String CNY = "CNY";
|
||||
|
||||
public PrepayWithRequestPaymentResponse prepayWithRequestPayment(Payable payable) {
|
||||
return this.prepayWithRequestPayment(payable.payableOutTradeNo(), payable.payableMoney(), payable.payableDescription(), payable.payableOpenId(), payable.payableAttach());
|
||||
public PrepayWithRequestPaymentResponse pay(Payable payable) {
|
||||
return this.prepayWithRequestPayment(payable.payableOutTradeNo(), payable.payableFen(), payable.payableDescription(), payable.payableOpenId(), payable.payableAttach());
|
||||
}
|
||||
|
||||
public PrepayWithRequestPaymentResponse prepayWithRequestPayment(String billNo, BigDecimal money, String description, String wxOpenId, String attach) {
|
||||
|
@ -59,9 +64,10 @@ public class WxPayService {
|
|||
|
||||
/**
|
||||
* 关闭支付订单
|
||||
*
|
||||
* @param billNo 平台订单编号
|
||||
*/
|
||||
public void closeOrder(String billNo) {
|
||||
public void closeByOutTradeNo(String billNo) {
|
||||
CloseOrderRequest request = new CloseOrderRequest();
|
||||
request.setMchid(wxPayConfig.getMerchantId());
|
||||
request.setOutTradeNo(billNo);
|
||||
|
@ -75,7 +81,7 @@ public class WxPayService {
|
|||
return jsapiService.queryOrderById(request);
|
||||
}
|
||||
|
||||
public Transaction queryOrderByOutTradeNo(String billNo) {
|
||||
public Transaction queryByOutTradeNo(String billNo) {
|
||||
QueryOrderByOutTradeNoRequest request = new QueryOrderByOutTradeNoRequest();
|
||||
request.setMchid(wxPayConfig.getMerchantId());
|
||||
request.setOutTradeNo(billNo);
|
||||
|
@ -87,7 +93,7 @@ public class WxPayService {
|
|||
*
|
||||
* @param refund
|
||||
*/
|
||||
public Refund refund(RefundAble refund) {
|
||||
public Refund refund(Refundable refund) {
|
||||
CreateRequest request = new CreateRequest();
|
||||
request.setOutTradeNo(refund.refundOutTradeNo());
|
||||
request.setOutRefundNo(refund.refundOutRefundNo());
|
||||
|
@ -100,6 +106,23 @@ public class WxPayService {
|
|||
return res;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isPaySuccessByOutTradeNo(String outTradeNo) {
|
||||
return isPaySuccess(this.queryByOutTradeNo(outTradeNo));
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isPaySuccess(Object result) {
|
||||
Transaction transaction = (Transaction) result;
|
||||
return WxPayUtil.isSuccess(transaction);
|
||||
}
|
||||
|
||||
@Override
|
||||
public LocalDateTime getPayTime(Object result) {
|
||||
Transaction transaction = (Transaction) result;
|
||||
return DateUtils.toLocalDateTimeByISO(transaction.getSuccessTime());
|
||||
}
|
||||
|
||||
private Payer getPayer(String openId) {
|
||||
Payer payer = new Payer();
|
||||
payer.setOpenid(openId);
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
package com.ruoyi.common.pay.yst.service;
|
||||
|
||||
import com.ruoyi.common.pay.wx.domain.Payable;
|
||||
import com.ruoyi.common.pay.Payable;
|
||||
import com.ruoyi.common.pay.yst.domain.bizRes.comsumptionApply.ChannelParamInfo;
|
||||
|
||||
/**
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
package com.ruoyi.common.pay.yst.service.impl;
|
||||
|
||||
import com.ruoyi.common.exception.ServiceException;
|
||||
import com.ruoyi.common.pay.wx.domain.Payable;
|
||||
import com.ruoyi.common.pay.Payable;
|
||||
import com.ruoyi.common.pay.yst.config.YstConfig;
|
||||
import com.ruoyi.common.pay.yst.constants.YstApi;
|
||||
import com.ruoyi.common.pay.yst.constants.YstTransCode;
|
||||
|
|
|
@ -53,4 +53,7 @@ public class Channel extends BaseEntity
|
|||
@JsonView(JsonViewProfile.App.class)
|
||||
private String picture;
|
||||
|
||||
@Excel(name = "适用平台(1微信 2支付宝)")
|
||||
@ApiModelProperty("适用平台(1微信 2支付宝)")
|
||||
private String platform;
|
||||
}
|
||||
|
|
|
@ -0,0 +1,63 @@
|
|||
package com.ruoyi.ss.channel.domain.enums;
|
||||
|
||||
import com.ruoyi.common.pay.PayApi;
|
||||
import com.ruoyi.common.pay.ali.service.AliPayService;
|
||||
import com.ruoyi.common.pay.syb.service.SybPayService;
|
||||
import com.ruoyi.common.pay.tm.TmPayService;
|
||||
import com.ruoyi.common.pay.wx.service.WxPayService;
|
||||
import com.ruoyi.common.utils.spring.SpringUtils;
|
||||
import com.ruoyi.ss.account.domain.enums.AccountType;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Getter;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/**
|
||||
* 渠道信息
|
||||
* @author 辉
|
||||
* 2024/3/12
|
||||
*/
|
||||
@Getter
|
||||
@AllArgsConstructor
|
||||
public enum ChannelEnum {
|
||||
|
||||
WECHAT(1L, "微信支付", AccountType.WECHAT, WxPayService.class, false),
|
||||
ALI(2L, "支付宝", AccountType.ALIPAY, AliPayService.class, true),
|
||||
BANK(3L, "银行卡", AccountType.BANK_CARD, null, false),
|
||||
BALANCE(4L, "余额支付", null, null, true),
|
||||
TL_WX(5L, "通联微信支付", null, SybPayService.class, true),
|
||||
TM_WX(6L, "太米微信支付", null, TmPayService.class, true);
|
||||
|
||||
private final Long type;
|
||||
private final String name;
|
||||
private final AccountType accountType;
|
||||
private final Class<? extends PayApi> payApi;
|
||||
private final Boolean isRefundSync; // 退款是否同步通知
|
||||
|
||||
public static ChannelEnum parse(Long type) {
|
||||
for (ChannelEnum value : ChannelEnum.values()) {
|
||||
if (Objects.equals(value.getType(), type)) {
|
||||
return value;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public static List<Long> asList(ChannelEnum...types) {
|
||||
return Arrays.stream(types).map(ChannelEnum::getType).collect(Collectors.toList());
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取支付API
|
||||
*/
|
||||
public static PayApi getPayApi(Long type) {
|
||||
ChannelEnum parse = parse(type);
|
||||
if (parse == null || parse.getPayApi() == null) {
|
||||
return null;
|
||||
}
|
||||
return SpringUtils.getBean(parse.getPayApi());
|
||||
}
|
||||
}
|
|
@ -0,0 +1,20 @@
|
|||
package com.ruoyi.ss.channel.domain.enums;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Getter;
|
||||
|
||||
/**
|
||||
* @author wjh
|
||||
* 2024/12/10
|
||||
*/
|
||||
@Getter
|
||||
@AllArgsConstructor
|
||||
public enum ChannelPlatform {
|
||||
|
||||
WX("1", "微信"),
|
||||
ALI("2", "支付宝");
|
||||
|
||||
private final String code;
|
||||
private final String msg;
|
||||
|
||||
}
|
|
@ -17,7 +17,8 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
|
|||
sc.service_rate,
|
||||
sc.cost_rate,
|
||||
sc.service_type,
|
||||
sc.picture
|
||||
sc.picture,
|
||||
sc.platform
|
||||
from sm_channel sc
|
||||
</sql>
|
||||
|
||||
|
@ -25,6 +26,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
|
|||
<if test="query.name != null and query.name != ''"> and sc.name like concat('%', #{query.name}, '%')</if>
|
||||
<if test="query.enabled != null "> and sc.enabled = #{query.enabled}</if>
|
||||
<if test="query.serviceType != null and query.serviceType != ''"> and sc.service_type = #{query.serviceType}</if>
|
||||
<if test="query.platform != null and query.platform != ''"> and platform = #{query.platform}</if>
|
||||
<if test="query.channelIds != null and query.channelIds.size() > 0 ">
|
||||
and sc.channel_id in
|
||||
<foreach item="item" collection="query.channelIds" open="(" separator="," close=")">
|
||||
|
@ -55,6 +57,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
|
|||
<if test="costRate != null">cost_rate,</if>
|
||||
<if test="serviceType != null">service_type,</if>
|
||||
<if test="picture != null">picture,</if>
|
||||
<if test="platform != null">platform,</if>
|
||||
</trim>
|
||||
<trim prefix="values (" suffix=")" suffixOverrides=",">
|
||||
<if test="channelId != null">#{channelId},</if>
|
||||
|
@ -64,6 +67,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
|
|||
<if test="costRate != null">#{costRate},</if>
|
||||
<if test="serviceType != null">#{serviceType},</if>
|
||||
<if test="picture != null">#{picture},</if>
|
||||
<if test="platform != null">#{platform},</if>
|
||||
</trim>
|
||||
</insert>
|
||||
|
||||
|
@ -76,6 +80,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
|
|||
<if test="data.costRate != null">cost_rate = #{data.costRate},</if>
|
||||
<if test="data.serviceType != null">service_type = #{data.serviceType},</if>
|
||||
<if test="data.picture != null">picture = #{data.picture},</if>
|
||||
<if test="data.platform != null">platform = #{data.platform},</if>
|
||||
</trim>
|
||||
where channel_id = #{data.channelId}
|
||||
</update>
|
||||
|
|
|
@ -69,7 +69,7 @@ public interface ChannelService
|
|||
*
|
||||
* @return
|
||||
*/
|
||||
List<ChannelVO> selectEnabledRechargeList();
|
||||
List<ChannelVO> selectEnabledRechargeList(ChannelQuery query);
|
||||
|
||||
/**
|
||||
* 查询充值渠道映射表
|
||||
|
|
|
@ -104,10 +104,9 @@ public class ChannelServiceImpl implements ChannelService
|
|||
}
|
||||
|
||||
@Override
|
||||
public List<ChannelVO> selectEnabledRechargeList() {
|
||||
ChannelQuery dto = new ChannelQuery();
|
||||
dto.setEnabled(true);
|
||||
return this.selectSmChannelList(dto);
|
||||
public List<ChannelVO> selectEnabledRechargeList(ChannelQuery query) {
|
||||
query.setEnabled(true);
|
||||
return this.selectSmChannelList(query);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -2,7 +2,7 @@ package com.ruoyi.ss.payBill.domain;
|
|||
|
||||
import com.ruoyi.common.annotation.Excel;
|
||||
import com.ruoyi.common.core.domain.BaseEntity;
|
||||
import com.ruoyi.common.pay.wx.domain.Payable;
|
||||
import com.ruoyi.common.pay.Payable;
|
||||
import com.ruoyi.common.pay.wx.domain.enums.AttachEnums;
|
||||
import io.swagger.annotations.ApiModelProperty;
|
||||
import lombok.Data;
|
||||
|
@ -71,7 +71,7 @@ public class PayBill extends BaseEntity implements Payable
|
|||
* 获取价格(分)
|
||||
*/
|
||||
@Override
|
||||
public BigDecimal payableMoney() {
|
||||
public BigDecimal payableFen() {
|
||||
return amount.multiply(BigDecimal.valueOf(100));
|
||||
}
|
||||
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
package com.ruoyi.ss.payBill.service.impl;
|
||||
|
||||
import com.ruoyi.ss.channel.domain.ChannelVO;
|
||||
import com.ruoyi.ss.channel.domain.enums.ChannelPlatform;
|
||||
import com.ruoyi.ss.channel.service.ChannelService;
|
||||
import com.ruoyi.ss.payBill.domain.PayBill;
|
||||
import com.ruoyi.ss.payBill.domain.PayBillVO;
|
||||
|
@ -10,7 +11,7 @@ import com.ruoyi.ss.payBill.service.PayBillConverter;
|
|||
import com.ruoyi.ss.timeBill.domain.TimeBill;
|
||||
import com.ruoyi.ss.transactionBill.domain.bo.RechargePayDepositBO;
|
||||
import com.ruoyi.ss.transactionBill.domain.dto.RechargePayBO;
|
||||
import com.ruoyi.ss.transactionBill.domain.enums.TransactionBillPayType;
|
||||
import com.ruoyi.ss.channel.domain.enums.ChannelEnum;
|
||||
import com.ruoyi.ss.transactionBill.domain.vo.TransactionBillVO;
|
||||
import com.ruoyi.ss.user.domain.SmUserVO;
|
||||
import com.ruoyi.ss.user.service.ISmUserService;
|
||||
|
@ -63,7 +64,7 @@ public class PayBillConverterImpl implements PayBillConverter {
|
|||
data.setChannelCost(this.calcChannelCost(channel, bill.getAmount()));
|
||||
|
||||
// 支付人
|
||||
if (TransactionBillPayType.WECHAT.getType().equals(data.getChannelId())) {
|
||||
if (ChannelEnum.WECHAT.getType().equals(data.getChannelId())) {
|
||||
data.setAccount(user.getWxOpenId());
|
||||
}
|
||||
return po;
|
||||
|
@ -110,8 +111,10 @@ public class PayBillConverterImpl implements PayBillConverter {
|
|||
po.setChannelCost(this.calcChannelCost(channel, order.getMoney()));
|
||||
|
||||
// 支付人
|
||||
if (TransactionBillPayType.wxList().contains(channel.getChannelId())) {
|
||||
if (ChannelPlatform.WX.getCode().equals(channel.getPlatform())) {
|
||||
po.setAccount(user.getWxOpenId());
|
||||
} else if (ChannelPlatform.ALI.getCode().equals(channel.getPlatform())) {
|
||||
po.setAccount(user.getAliOpenId());
|
||||
}
|
||||
|
||||
return po;
|
||||
|
@ -149,8 +152,10 @@ public class PayBillConverterImpl implements PayBillConverter {
|
|||
po.setChannelCost(this.calcChannelCost(channel, order.getSuitPrice()));
|
||||
|
||||
// 支付人
|
||||
if (TransactionBillPayType.wxList().contains(channel.getChannelId())) {
|
||||
if (ChannelPlatform.WX.getCode().equals(channel.getPlatform())) {
|
||||
po.setAccount(user.getWxOpenId());
|
||||
} else if (ChannelPlatform.ALI.getCode().equals(channel.getPlatform())) {
|
||||
po.setAccount(user.getAliOpenId());
|
||||
}
|
||||
|
||||
return po;
|
||||
|
|
|
@ -4,6 +4,8 @@ import com.ruoyi.common.core.redis.RedisLock;
|
|||
import com.ruoyi.common.core.redis.enums.RedisLockKey;
|
||||
import com.ruoyi.common.domain.vo.LocalDateDecimalVO;
|
||||
import com.ruoyi.common.exception.ServiceException;
|
||||
import com.ruoyi.common.pay.PayApi;
|
||||
import com.ruoyi.common.pay.ali.service.AliPayService;
|
||||
import com.ruoyi.common.pay.syb.enums.SybTrxStatus;
|
||||
import com.ruoyi.common.pay.syb.service.SybPayService;
|
||||
import com.ruoyi.common.pay.tm.TmPayService;
|
||||
|
@ -14,6 +16,7 @@ import com.ruoyi.common.pay.wx.util.WxPayUtil;
|
|||
import com.ruoyi.common.utils.DateUtils;
|
||||
import com.ruoyi.common.utils.ServiceUtil;
|
||||
import com.ruoyi.common.utils.SnowFlakeUtil;
|
||||
import com.ruoyi.common.utils.StringUtils;
|
||||
import com.ruoyi.common.utils.collection.CollectionUtils;
|
||||
import com.ruoyi.common.utils.spring.SpringUtils;
|
||||
import com.ruoyi.ss.payBill.domain.PayBill;
|
||||
|
@ -29,12 +32,11 @@ import com.ruoyi.ss.payBill.domain.vo.PayResultVO;
|
|||
import com.ruoyi.ss.payBill.interfaces.AfterPay;
|
||||
import com.ruoyi.ss.payBill.interfaces.AfterRefund;
|
||||
import com.ruoyi.ss.payBill.mapper.PayBillMapper;
|
||||
import com.ruoyi.ss.payBill.service.PayBillConverter;
|
||||
import com.ruoyi.ss.payBill.service.PayBillService;
|
||||
import com.ruoyi.ss.refund.domain.RefundVO;
|
||||
import com.ruoyi.ss.refund.service.RefundConverter;
|
||||
import com.ruoyi.ss.refund.service.RefundService;
|
||||
import com.ruoyi.ss.transactionBill.domain.enums.TransactionBillPayType;
|
||||
import com.ruoyi.ss.channel.domain.enums.ChannelEnum;
|
||||
import com.wechat.pay.java.service.payments.model.Transaction;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
|
@ -80,15 +82,15 @@ public class PayBillServiceImpl implements PayBillService
|
|||
@Autowired
|
||||
private RefundService refundService;
|
||||
|
||||
@Autowired
|
||||
private PayBillConverter payBillConverter;
|
||||
|
||||
@Autowired
|
||||
private SybPayService sybPayService;
|
||||
|
||||
@Autowired
|
||||
private TmPayService tmPayService;
|
||||
|
||||
@Autowired
|
||||
private AliPayService aliPayService;
|
||||
|
||||
/**
|
||||
* 查询支付订单
|
||||
*
|
||||
|
@ -166,6 +168,7 @@ public class PayBillServiceImpl implements PayBillService
|
|||
@Override
|
||||
public DoPayVO createPayBill(PayBill bill) {
|
||||
ServiceUtil.assertion(bill == null, "待新增的支付订单不存在");
|
||||
ServiceUtil.assertion(StringUtils.isBlank(bill.getAccount()), "用户支付账号不存在");
|
||||
// 锁
|
||||
String lockKey = bill.getBstType() + bill.getBstId();
|
||||
if (!redisLock.lock(RedisLockKey.PAY_BILL, lockKey)) {
|
||||
|
@ -229,27 +232,22 @@ public class PayBillServiceImpl implements PayBillService
|
|||
for (PayBillVO bill : payingList) {
|
||||
// 关闭支付中的订单
|
||||
if (PayBillStatus.PAYING.getStatus().equals(bill.getStatus())) {
|
||||
// 微信
|
||||
if (TransactionBillPayType.WECHAT.getType().equals(bill.getChannelId())) {
|
||||
wxPayService.closeOrder(bill.getPayNo());
|
||||
// 获取支付API
|
||||
PayApi payApi = ChannelEnum.getPayApi(bill.getChannelId());
|
||||
if (payApi == null) {
|
||||
continue;
|
||||
}
|
||||
// 通联微信
|
||||
else if (TransactionBillPayType.TL_WX.getType().equals(bill.getChannelId())) {
|
||||
try {
|
||||
sybPayService.closeOrderWx(bill.getPayNo());
|
||||
} catch (Exception e) {
|
||||
Map<String, String> result = sybPayService.queryOrderByOutTradeNo(bill.getPayNo());
|
||||
if (SybTrxStatus.isSuccess(result)) {
|
||||
throw new ServiceException("交易已成功,无法关闭");
|
||||
} else {
|
||||
log.error("关闭通联支付订单出错:{}", e.getMessage());
|
||||
}
|
||||
// 调用关闭API
|
||||
try {
|
||||
payApi.closeByOutTradeNo(bill.getPayNo());
|
||||
} catch (Exception e) {
|
||||
// 关闭失败,尝试查询订单信息,判断是否已经支付成功
|
||||
if (payApi.isPaySuccessByOutTradeNo(bill.getPayNo())) {
|
||||
throw new ServiceException("当前交易已成功,无法关闭");
|
||||
} else {
|
||||
log.error("关闭支付订单失败: payNo = {} 原因:{}", bill.getPayNo(), e.getMessage());
|
||||
}
|
||||
}
|
||||
// 太米微信
|
||||
else if (TransactionBillPayType.TM_WX.getType().equals(bill.getChannelId())) {
|
||||
tmPayService.closeOrder(bill.getPayNo());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -341,15 +339,9 @@ public class PayBillServiceImpl implements PayBillService
|
|||
this.handleSuccess(bill.getPayNo(), LocalDateTime.now());
|
||||
}, 1L, TimeUnit.SECONDS);
|
||||
} else {
|
||||
if (TransactionBillPayType.WECHAT.getType().equals(bill.getChannelId())) {
|
||||
vo.setPayParams(wxPayService.prepayWithRequestPayment(bill));
|
||||
} else if (TransactionBillPayType.TL_WX.getType().equals(bill.getChannelId())) {
|
||||
vo.setPayParams(sybPayService.prepayWxApp(bill));
|
||||
} else if (TransactionBillPayType.TM_WX.getType().equals(bill.getChannelId())) {
|
||||
vo.setPayParams(tmPayService.wxPay(bill));
|
||||
} else {
|
||||
throw new ServiceException("暂不支持该支付方式");
|
||||
}
|
||||
PayApi payApi = ChannelEnum.getPayApi(bill.getChannelId());
|
||||
ServiceUtil.assertion(payApi == null, "暂不支持该支付方式");
|
||||
vo.setPayParams(payApi.pay(bill));
|
||||
// 异步刷新支付结果
|
||||
scheduledExecutorService.schedule(() -> {
|
||||
this.refreshPayResultMaxCount(bill, 20L, TimeUnit.SECONDS, 10);
|
||||
|
@ -524,33 +516,18 @@ public class PayBillServiceImpl implements PayBillService
|
|||
return PayResultVO.success(LocalDateTime.now());
|
||||
}
|
||||
|
||||
// 查询第三方支付渠道
|
||||
if (TransactionBillPayType.WECHAT.getType().equals(bill.getChannelId())) {
|
||||
// 微信支付
|
||||
Transaction transaction = wxPayService.queryOrderByOutTradeNo(bill.getPayNo());
|
||||
boolean success = WxPayUtil.isSuccess(transaction);
|
||||
if (success) {
|
||||
return PayResultVO.success(DateUtils.toLocalDateTimeByISO(transaction.getSuccessTime()), transaction);
|
||||
} else {
|
||||
return PayResultVO.fail("暂未支付成功");
|
||||
}
|
||||
} else if (TransactionBillPayType.TL_WX.getType().equals(bill.getChannelId())) {
|
||||
// 通联微信支付
|
||||
Map<String, String> result = sybPayService.queryOrderByOutTradeNo(bill.getPayNo());
|
||||
if (SybTrxStatus.isSuccess(result)) {
|
||||
return PayResultVO.success(DateUtils.toLocalDate(result.get("fintime"), "yyyyMMddHHmmss"), result);
|
||||
} else {
|
||||
return PayResultVO.fail("暂未支付成功");
|
||||
}
|
||||
} else if (TransactionBillPayType.TM_WX.getType().equals(bill.getChannelId())) {
|
||||
// 太米微信支付
|
||||
TmTradeInfo result = tmPayService.orderQuery(bill.getPayNo());
|
||||
if (result != null && TmPayStatus.isSuccess(result.getPayStatus())) {
|
||||
return PayResultVO.success(DateUtils.toLocalDateTime(result.getPayTime(), "yyyy-MM-dd HH:mm:ss"), result); // TODO 支付时间
|
||||
} else {
|
||||
return PayResultVO.fail("暂未支付成功");
|
||||
}
|
||||
// 获取支付API
|
||||
PayApi payApi = ChannelEnum.getPayApi(bill.getChannelId());
|
||||
if (payApi == null) {
|
||||
return PayResultVO.fail("暂不支持该支付方式");
|
||||
}
|
||||
|
||||
// 获取支付结果
|
||||
Object result = payApi.queryByOutTradeNo(bill.getPayNo());
|
||||
if (payApi.isPaySuccess(result)) {
|
||||
return PayResultVO.success(payApi.getPayTime(result), result);
|
||||
} else {
|
||||
return PayResultVO.fail("暂未支付成功");
|
||||
}
|
||||
return PayResultVO.fail("暂不支持该支付方式");
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
package com.ruoyi.ss.refund.domain;
|
||||
|
||||
import com.ruoyi.common.pay.wx.domain.RefundAble;
|
||||
import com.ruoyi.common.pay.Refundable;
|
||||
import com.wechat.pay.java.service.refund.model.AmountReq;
|
||||
import io.swagger.annotations.ApiModelProperty;
|
||||
import lombok.Data;
|
||||
|
@ -12,7 +12,7 @@ import java.math.BigDecimal;
|
|||
* 2024/7/9
|
||||
*/
|
||||
@Data
|
||||
public class RefundVO extends Refund implements RefundAble {
|
||||
public class RefundVO extends Refund implements Refundable {
|
||||
|
||||
@ApiModelProperty("原订单编号")
|
||||
private String payNo;
|
||||
|
|
|
@ -2,6 +2,7 @@ package com.ruoyi.ss.refund.service.impl;
|
|||
|
||||
import com.ruoyi.common.domain.vo.LocalDateDecimalVO;
|
||||
import com.ruoyi.common.exception.ServiceException;
|
||||
import com.ruoyi.common.pay.PayApi;
|
||||
import com.ruoyi.common.pay.syb.enums.SybTrxStatus;
|
||||
import com.ruoyi.common.pay.syb.service.SybPayService;
|
||||
import com.ruoyi.common.pay.tm.TmPayService;
|
||||
|
@ -18,14 +19,13 @@ import com.ruoyi.ss.refund.domain.RefundVO;
|
|||
import com.ruoyi.ss.refund.domain.enums.RefundStatus;
|
||||
import com.ruoyi.ss.refund.mapper.RefundMapper;
|
||||
import com.ruoyi.ss.refund.service.RefundService;
|
||||
import com.ruoyi.ss.transactionBill.domain.enums.TransactionBillPayType;
|
||||
import com.ruoyi.ss.channel.domain.enums.ChannelEnum;
|
||||
import com.ruoyi.ss.transactionBill.service.TransactionBillService;
|
||||
import org.apache.commons.lang.StringUtils;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.support.TransactionTemplate;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.ScheduledExecutorService;
|
||||
|
@ -193,38 +193,22 @@ public class RefundServiceImpl implements RefundService
|
|||
int insertRefund = this.insertRefund(refund);
|
||||
ServiceUtil.assertion(insertRefund != 1, "创建退款订单失败");
|
||||
|
||||
RefundVO refundVO = this.selectRefundByRefundNo(refund.getRefundNo());
|
||||
RefundVO vo = this.selectRefundByRefundNo(refund.getRefundNo());
|
||||
|
||||
// 发起退款
|
||||
// 微信
|
||||
if (TransactionBillPayType.WECHAT.getType().equals(refund.getChannelId())) {
|
||||
wxPayService.refund(refundVO);
|
||||
}
|
||||
// 通联微信
|
||||
else if (TransactionBillPayType.TL_WX.getType().equals(refund.getChannelId())) {
|
||||
Map<String, String> refundResult = sybPayService.refundWx(refundVO);
|
||||
String trxStatus = refundResult.get("trxstatus");
|
||||
// 当状态不为空,则判断是否处理退款成功
|
||||
if (trxStatus != null) {
|
||||
ServiceUtil.assertion(!SybTrxStatus.isSuccess(trxStatus), "发起退款失败:" + refundResult.get("errmsg"));
|
||||
// 通联退款是同步通知,直接处理退款成功
|
||||
scheduledExecutorService.schedule(() -> {
|
||||
this.handleRefundSuccess(refund.getRefundNo());
|
||||
}, 0, TimeUnit.SECONDS);
|
||||
}
|
||||
}
|
||||
// 太米支付
|
||||
else if (TransactionBillPayType.TM_WX.getType().equals(refund.getChannelId())) {
|
||||
RefundInfo refundResult = tmPayService.refund(refundVO);
|
||||
ServiceUtil.assertion(!TmRefundStatus.isSuccess(refundResult.getRefundStatus().getCode()), "发起退款失败:" + refundResult.getRefundMessage());
|
||||
// 太米退款是同步通知,直接处理退款成功
|
||||
scheduledExecutorService.schedule(() -> {
|
||||
handleRefundSuccess(refund.getRefundNo());
|
||||
}, 10, TimeUnit.SECONDS);
|
||||
}
|
||||
else {
|
||||
PayApi payApi = ChannelEnum.getPayApi(refund.getChannelId());
|
||||
if (payApi == null) {
|
||||
throw new ServiceException("当前支付方式不支持退款");
|
||||
}
|
||||
payApi.refund(vo);
|
||||
|
||||
// 判断是否同步通知,若是则直接处理支付成功
|
||||
ChannelEnum channelEnum = ChannelEnum.parse(refund.getChannelId());
|
||||
if (channelEnum != null && channelEnum.getIsRefundSync() != null && channelEnum.getIsRefundSync()) {
|
||||
scheduledExecutorService.schedule(() -> {
|
||||
this.handleRefundSuccess(refund.getRefundNo());
|
||||
}, 10, TimeUnit.SECONDS);
|
||||
}
|
||||
|
||||
return insertRefund;
|
||||
});
|
||||
|
@ -248,16 +232,16 @@ public class RefundServiceImpl implements RefundService
|
|||
}
|
||||
|
||||
// 通联微信
|
||||
if (TransactionBillPayType.TL_WX.getType().equals(refund.getChannelId())) {
|
||||
Map<String, String> params = sybPayService.queryOrderByOutTradeNo(refund.getRefundNo());
|
||||
String trxStatus = params.get("trxstatus");
|
||||
if (SybTrxStatus.isSuccess(trxStatus)) {
|
||||
// 退款成功
|
||||
scheduledExecutorService.schedule(() -> {
|
||||
this.handleRefundSuccess(refund.getRefundNo());
|
||||
}, 0, TimeUnit.SECONDS);
|
||||
}
|
||||
}
|
||||
// if (ChannelEnum.TL_WX.getType().equals(refund.getChannelId())) {
|
||||
// Map<String, String> params = sybPayService.queryByOutTradeNo(refund.getRefundNo());
|
||||
// String trxStatus = params.get("trxstatus");
|
||||
// if (SybTrxStatus.isSuccess(trxStatus)) {
|
||||
// // 退款成功
|
||||
// scheduledExecutorService.schedule(() -> {
|
||||
// this.handleRefundSuccess(refund.getRefundNo());
|
||||
// }, 0, TimeUnit.SECONDS);
|
||||
// }
|
||||
// }
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
|
|
@ -8,7 +8,7 @@ import com.ruoyi.common.core.domain.BaseEntity;
|
|||
import com.ruoyi.common.core.domain.JsonViewProfile;
|
||||
import com.ruoyi.common.core.domain.ValidGroup;
|
||||
import com.ruoyi.ss.transactionBill.domain.enums.TransactionBillType;
|
||||
import com.ruoyi.common.pay.wx.domain.Payable;
|
||||
import com.ruoyi.common.pay.Payable;
|
||||
import com.ruoyi.common.pay.wx.domain.enums.AttachEnums;
|
||||
import com.ruoyi.system.valid.DictValid;
|
||||
import io.swagger.annotations.ApiModelProperty;
|
||||
|
@ -336,7 +336,7 @@ public class TransactionBill extends BaseEntity implements Payable
|
|||
* 获取价格(分)
|
||||
*/
|
||||
@Override
|
||||
public BigDecimal payableMoney() {
|
||||
public BigDecimal payableFen() {
|
||||
return money.multiply(BigDecimal.valueOf(100));
|
||||
}
|
||||
|
||||
|
|
|
@ -1,53 +0,0 @@
|
|||
package com.ruoyi.ss.transactionBill.domain.enums;
|
||||
|
||||
import com.ruoyi.common.exception.ServiceException;
|
||||
import com.ruoyi.ss.account.domain.enums.AccountType;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Getter;
|
||||
import nonapi.io.github.classgraph.utils.LogNode;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/**
|
||||
* 支付方式(打款方式)
|
||||
* @author 辉
|
||||
* 2024/3/12
|
||||
*/
|
||||
@Getter
|
||||
@AllArgsConstructor
|
||||
public enum TransactionBillPayType {
|
||||
|
||||
WECHAT(1L, "微信支付", AccountType.WECHAT),
|
||||
ALI(2L, "支付宝", AccountType.ALIPAY),
|
||||
BANK(3L, "银行卡", AccountType.BANK_CARD),
|
||||
BALANCE(4L, "余额支付", null),
|
||||
TL_WX(5L, "通联微信支付", null),
|
||||
TM_WX(6L, "太米微信支付", null);
|
||||
|
||||
private final Long type;
|
||||
private final String name;
|
||||
private final AccountType accountType;
|
||||
|
||||
public static TransactionBillPayType parse(Long type) {
|
||||
for (TransactionBillPayType value : TransactionBillPayType.values()) {
|
||||
if (Objects.equals(value.getType(), type)) {
|
||||
return value;
|
||||
}
|
||||
}
|
||||
throw new ServiceException("不存在值为" + type + "的支付方式(打款方式)");
|
||||
}
|
||||
|
||||
public static List<Long> asList(TransactionBillPayType ...types) {
|
||||
return Arrays.stream(types).map(TransactionBillPayType::getType).collect(Collectors.toList());
|
||||
}
|
||||
|
||||
/**
|
||||
* 微信支付列表
|
||||
*/
|
||||
public static List<Long> wxList() {
|
||||
return asList(WECHAT, TL_WX, TM_WX);
|
||||
}
|
||||
}
|
|
@ -42,7 +42,7 @@ public class TransactionBillVO extends TransactionBill implements IotDevice {
|
|||
private String channelName;
|
||||
|
||||
@ApiModelProperty("商户手机号")
|
||||
@JsonView(JsonViewProfile.AppMch.class)
|
||||
@JsonView(JsonViewProfile.App.class)
|
||||
private String mchMobile;
|
||||
|
||||
@ApiModelProperty("设备总用电量")
|
||||
|
|
|
@ -100,7 +100,6 @@ public class TransactionBillConverterImpl implements TransactionBillConverter {
|
|||
|
||||
SmUserVO user = userService.selectSmUserByUserId(SecurityUtils.getUserId());
|
||||
ServiceUtil.assertion(user == null, "用户不存在");
|
||||
ServiceUtil.assertion(user.getWxOpenId() == null, "用户微信openId为空");
|
||||
|
||||
RechargeBO bo = new RechargeBO();
|
||||
bo.setDevice(device);
|
||||
|
|
|
@ -4,12 +4,13 @@ import com.fasterxml.jackson.annotation.JsonView;
|
|||
import com.ruoyi.common.core.controller.BaseController;
|
||||
import com.ruoyi.common.core.domain.AjaxResult;
|
||||
import com.ruoyi.common.core.domain.JsonViewProfile;
|
||||
import com.ruoyi.ss.channel.domain.ChannelQuery;
|
||||
import com.ruoyi.ss.channel.service.ChannelService;
|
||||
import com.ruoyi.ss.transactionBill.service.TransactionBillService;
|
||||
import io.swagger.annotations.ApiOperation;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RequestParam;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
/**
|
||||
|
@ -26,8 +27,10 @@ public class AppChannelController extends BaseController {
|
|||
@ApiOperation("获取充值渠道列表")
|
||||
@JsonView(JsonViewProfile.App.class)
|
||||
@GetMapping("/enabledList")
|
||||
public AjaxResult getRechargeEnabledList() {
|
||||
return success(channelService.selectEnabledRechargeList());
|
||||
public AjaxResult getRechargeEnabledList(@RequestParam(required = false, defaultValue = "1") String platform) {
|
||||
ChannelQuery query = new ChannelQuery();
|
||||
query.setPlatform(platform);
|
||||
return success(channelService.selectEnabledRechargeList(query));
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -20,7 +20,7 @@ import com.ruoyi.common.utils.http.HttpUtils;
|
|||
import com.ruoyi.ss.payBill.service.PayBillService;
|
||||
import com.ruoyi.ss.refund.service.RefundService;
|
||||
import com.ruoyi.ss.transactionBill.domain.dto.RechargePayBO;
|
||||
import com.ruoyi.ss.transactionBill.domain.enums.TransactionBillPayType;
|
||||
import com.ruoyi.ss.channel.domain.enums.ChannelEnum;
|
||||
import com.ruoyi.ss.transactionBill.domain.vo.TransactionBillVO;
|
||||
import com.ruoyi.ss.transactionBill.service.TransactionBillConverter;
|
||||
import com.ruoyi.ss.transactionBill.service.TransactionBillService;
|
||||
|
@ -41,7 +41,6 @@ import org.springframework.http.ResponseEntity;
|
|||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.Map;
|
||||
import java.util.TreeMap;
|
||||
|
||||
|
@ -80,7 +79,7 @@ public class AppPayController extends BaseController {
|
|||
if (bill == null || bill.getUserId() == null || !bill.getUserId().equals(getUserId())) {
|
||||
return error("这不是您的订单");
|
||||
}
|
||||
RechargePayBO bo = transactionBillConverter.toRechargePayBO(bill, TransactionBillPayType.WECHAT.getType());
|
||||
RechargePayBO bo = transactionBillConverter.toRechargePayBO(bill, ChannelEnum.WECHAT.getType());
|
||||
return success(transactionBillService.pay(bo));
|
||||
}
|
||||
|
||||
|
|
|
@ -4,10 +4,8 @@ import com.ruoyi.common.core.controller.BaseController;
|
|||
import com.ruoyi.common.core.domain.AjaxResult;
|
||||
import com.ruoyi.ss.timeBill.domain.TimeBillVO;
|
||||
import com.ruoyi.ss.timeBill.domain.dto.TimeBillAddOrderDTO;
|
||||
import com.ruoyi.ss.timeBill.domain.dto.TimeBillPayDTO;
|
||||
import com.ruoyi.ss.timeBill.service.TimeBillService;
|
||||
import com.ruoyi.ss.timeBill.service.TimeBillValidator;
|
||||
import com.ruoyi.ss.transactionBill.domain.enums.TransactionBillPayType;
|
||||
import io.swagger.annotations.ApiOperation;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
|
|
|
@ -148,3 +148,5 @@ ali:
|
|||
alipayPublicKey: MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAi1vuaEyUkCgagVodfOJp/rk1gwVzs8f/QzEXAEUwZZne+VE8be0rUv9SLY0uOjixanw0yhG9LinHJlePCvuK0Y31Cxx0BXgOt27nGTSqm4oINFYd5WL1vNMPzPE2gat+7ohO3h6FRlmsxsq9W5ZRkko+04Be4lEGZ+Ter/b2v3m4I3CzX6kr42e39QlDRUpD9l9ixpkmfEatdDf01Xp++Tvr/3EZcYoG3oPGztI7B8Kw8KV/6he3ZBlGROWz8ywZSBtR294Y1PRDv+3QXC3nr7J6OrTbnvj+MAtKmwjdkFHiFVr3gfenzeI87LnXrDPahda7Mn6ToQ1NU9tsWCcJgQIDAQAB
|
||||
# AES秘钥
|
||||
aesPrivateKey: FGhCgOURrXkhGs36PUTHfg==
|
||||
# 通知地址
|
||||
notifyUrl: http://124.221.246.124:2290/app/pay/notify/ali
|
||||
|
|
|
@ -148,3 +148,5 @@ ali:
|
|||
alipayPublicKey: MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAi1vuaEyUkCgagVodfOJp/rk1gwVzs8f/QzEXAEUwZZne+VE8be0rUv9SLY0uOjixanw0yhG9LinHJlePCvuK0Y31Cxx0BXgOt27nGTSqm4oINFYd5WL1vNMPzPE2gat+7ohO3h6FRlmsxsq9W5ZRkko+04Be4lEGZ+Ter/b2v3m4I3CzX6kr42e39QlDRUpD9l9ixpkmfEatdDf01Xp++Tvr/3EZcYoG3oPGztI7B8Kw8KV/6he3ZBlGROWz8ywZSBtR294Y1PRDv+3QXC3nr7J6OrTbnvj+MAtKmwjdkFHiFVr3gfenzeI87LnXrDPahda7Mn6ToQ1NU9tsWCcJgQIDAQAB
|
||||
# AES秘钥
|
||||
aesPrivateKey: FGhCgOURrXkhGs36PUTHfg==
|
||||
# 通知地址
|
||||
notifyUrl: https://kg.chuangtewl.com/prod-api/app/pay/notify/ali
|
||||
|
|
Loading…
Reference in New Issue
Block a user