完成支付请求、重新发起请求、实际支付(通知回调为测试),需要跟踪状态轮询时是否更新数据库中的状态;退款申请已经完成,还需要根据业务系统增加审核相关字段
This commit is contained in:
parent
e2985dd256
commit
5a94e8da43
@ -32,12 +32,12 @@
|
||||
<artifactId>ebike-feign</artifactId>
|
||||
<version>0.0.1-SNAPSHOT</version>
|
||||
</dependency>
|
||||
<!-- 微信支付SDK -->
|
||||
<dependency>
|
||||
<groupId>com.github.wechatpay-apiv3</groupId>
|
||||
<artifactId>wechatpay-java</artifactId>
|
||||
<version>0.2.17</version>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-web</artifactId>
|
||||
<version>${boot.version}</version>
|
||||
</dependency>
|
||||
|
||||
<!-- mybatis-flex -->
|
||||
<dependency>
|
||||
<groupId>com.mybatis-flex</groupId>
|
||||
@ -50,6 +50,33 @@
|
||||
<version>${mybatis-flex.version}</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
<!-- nacos客户端依赖包 -->
|
||||
<dependency>
|
||||
<groupId>com.alibaba.cloud</groupId>
|
||||
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
|
||||
<version>${nacos.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.mysql</groupId>
|
||||
<artifactId>mysql-connector-j</artifactId>
|
||||
<version>${mysql.version}</version>
|
||||
<scope>runtime</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter</artifactId>
|
||||
<version>${boot.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.cloud</groupId>
|
||||
<artifactId>spring-cloud-starter-loadbalancer</artifactId>
|
||||
</dependency>
|
||||
<!-- 微信支付SDK -->
|
||||
<dependency>
|
||||
<groupId>com.github.wechatpay-apiv3</groupId>
|
||||
<artifactId>wechatpay-java</artifactId>
|
||||
<version>0.2.17</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.projectlombok</groupId>
|
||||
<artifactId>lombok</artifactId>
|
||||
@ -101,28 +128,6 @@
|
||||
<artifactId>fastjson2</artifactId>
|
||||
<version>${fastjson.version}</version>
|
||||
</dependency>
|
||||
<!-- nacos客户端依赖包 -->
|
||||
<dependency>
|
||||
<groupId>com.alibaba.cloud</groupId>
|
||||
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
|
||||
<version>${nacos.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.cloud</groupId>
|
||||
<artifactId>spring-cloud-starter-loadbalancer</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.mysql</groupId>
|
||||
<artifactId>mysql-connector-j</artifactId>
|
||||
<version>${mysql.version}</version>
|
||||
<scope>runtime</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>jakarta.servlet</groupId>
|
||||
<artifactId>jakarta.servlet-api</artifactId>
|
||||
<version>6.0.0</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
<!-- for test only -->
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
|
||||
@ -3,6 +3,7 @@ package com.cdzy.payment;
|
||||
import org.mybatis.spring.annotation.MapperScan;
|
||||
import org.springframework.boot.SpringApplication;
|
||||
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||
import org.springframework.cloud.openfeign.EnableFeignClients;
|
||||
import org.springframework.scheduling.annotation.EnableScheduling;
|
||||
|
||||
/**
|
||||
@ -14,6 +15,7 @@ import org.springframework.scheduling.annotation.EnableScheduling;
|
||||
*/
|
||||
@SpringBootApplication
|
||||
@MapperScan("com.cdzy.payment.mapper")
|
||||
@EnableFeignClients(basePackages = "com.ebike.feign")
|
||||
public class EbikePaymentApplication {
|
||||
public static void main(String[] args) {
|
||||
SpringApplication.run(EbikePaymentApplication.class, args);
|
||||
|
||||
@ -3,6 +3,7 @@ package com.cdzy.payment.config;
|
||||
import com.wechat.pay.java.core.Config;
|
||||
import com.wechat.pay.java.core.RSAPublicKeyConfig;
|
||||
import com.wechat.pay.java.core.cipher.RSASigner;
|
||||
import com.wechat.pay.java.core.cipher.Signer;
|
||||
import com.wechat.pay.java.core.util.PemUtil;
|
||||
import com.wechat.pay.java.service.payments.jsapi.JsapiService;
|
||||
import com.wechat.pay.java.service.refund.RefundService;
|
||||
@ -62,9 +63,14 @@ public class WxPayConfig {
|
||||
private String refundNotifyUrl;
|
||||
/**
|
||||
* 支付、退款过期时间(分钟)
|
||||
* 默认5分钟,超过5分钟订单会自动关闭
|
||||
* 默认24小时,超过24小时订单会自动关闭
|
||||
*/
|
||||
private Integer expireMinute = 5;
|
||||
private Integer expireMinute = 1440;
|
||||
/**
|
||||
* 定时任务执行表达式
|
||||
* 默认每12小时执行1次
|
||||
*/
|
||||
private String cronExpression = "0 0 0,12 * * ?";
|
||||
|
||||
@Bean
|
||||
public Config certificateConfig() {
|
||||
@ -90,9 +96,8 @@ public class WxPayConfig {
|
||||
}
|
||||
|
||||
@Bean
|
||||
public RSASigner wxRsaSigner(){
|
||||
PrivateKey privateKey = PemUtil.loadPrivateKeyFromPath(privateKeyPath);
|
||||
return new RSASigner(merchantSerialNumber, privateKey);
|
||||
public Signer wxRsaSigner(Config certificateConfig){
|
||||
return certificateConfig.createSigner();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -31,7 +31,7 @@ public class EbikeWxPaymentController {
|
||||
* @param orderId 骑行订单id
|
||||
* @return 下单成功返回true,否则返回false
|
||||
*/
|
||||
@PostMapping("/prepay")
|
||||
@GetMapping("/prepay")
|
||||
public JsonResult<?> prepay(@RequestParam(name = "orderId") String orderId) {
|
||||
JSONObject r = wxPayService.prepay(orderId);
|
||||
return r.containsKey("error")?JsonResult.failed("下单失败: "+ r.getString("error")):JsonResult.success(r);
|
||||
@ -44,8 +44,8 @@ public class EbikeWxPaymentController {
|
||||
* @return 支付订单信息
|
||||
*/
|
||||
@GetMapping("/queryOrder/{orderId}")
|
||||
public JsonResult<?> queryOrderByOutTradeNo(@PathVariable String orderId) {
|
||||
Transaction r = wxPayService.queryOrderByOutTradeNo(orderId);
|
||||
public JsonResult<?> queryOrderByOrderId(@PathVariable(name = "orderId") String orderId) {
|
||||
Transaction r = wxPayService.queryOrderByOrderId(orderId);
|
||||
return r == null?JsonResult.failed(String.format("骑行订单号{%s}查询支付订单失败", orderId)):JsonResult.success(r);
|
||||
}
|
||||
|
||||
@ -56,8 +56,8 @@ public class EbikeWxPaymentController {
|
||||
* @return 订单信息支付状态
|
||||
*/
|
||||
@GetMapping("/queryOrderStatus/{orderId}")
|
||||
public JsonResult<?> queryOrderStatusById(@PathVariable String orderId) {
|
||||
HandleNotifyResult r = wxPayService.queryOrderStatusByOutTradeNo(orderId);
|
||||
public JsonResult<?> queryOrderStatusById(@PathVariable(name = "orderId") String orderId) {
|
||||
HandleNotifyResult r = wxPayService.queryOrderStatusByOrderId(orderId);
|
||||
return JsonResult.success(r);
|
||||
}
|
||||
|
||||
@ -93,7 +93,7 @@ public class EbikeWxPaymentController {
|
||||
* @return 退款信息
|
||||
*/
|
||||
@GetMapping("/queryRefund/{refundId}")
|
||||
public JsonResult<?> refundQuery(@PathVariable String refundId) {
|
||||
public JsonResult<?> refundQuery(@PathVariable(name = "refundId") String refundId) {
|
||||
Refund r = wxPayService.queryRefundByOutNo(refundId);
|
||||
return r == null?JsonResult.failed(String.format("退款单号{%s}查询退款失败", refundId)):JsonResult.success(r);
|
||||
}
|
||||
|
||||
@ -2,8 +2,8 @@ package com.cdzy.payment.model.dto;
|
||||
|
||||
import com.alibaba.fastjson2.JSONObject;
|
||||
import com.alibaba.fastjson2.annotation.JSONField;
|
||||
import com.wechat.pay.java.core.cipher.RSASigner;
|
||||
import com.wechat.pay.java.core.cipher.SignatureResult;
|
||||
import com.wechat.pay.java.core.cipher.Signer;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
@ -49,15 +49,11 @@ public class WxJsapiPromptDto {
|
||||
*/
|
||||
private String paySign;
|
||||
|
||||
public JSONObject toJson(RSASigner rsaSigner) {
|
||||
public JSONObject toJson(Signer rsaSigner) {
|
||||
try{
|
||||
// 计算签名
|
||||
StringJoiner signMsg = new StringJoiner("\n");
|
||||
signMsg.add(appId);
|
||||
signMsg.add(timeStamp);
|
||||
signMsg.add(nonceStr);
|
||||
signMsg.add(extension);
|
||||
SignatureResult sign = rsaSigner.sign(signMsg.toString());
|
||||
String signMsg = appId + "\n" + timeStamp + "\n" + nonceStr + "\n" + extension + "\n";
|
||||
SignatureResult sign = rsaSigner.sign(signMsg);
|
||||
this.paySign = sign.getSign();
|
||||
//result.put("package", result.remove("extension"));
|
||||
return JSONObject.parseObject(JSONObject.toJSONString(this));
|
||||
|
||||
@ -40,7 +40,7 @@ public class EbikePayment implements Serializable {
|
||||
private String orderId;
|
||||
|
||||
/**
|
||||
* 预支付交易会话标识;有效期为2小时
|
||||
* 支付交易用订单编号,重新请求时需要更新
|
||||
*/
|
||||
private String paymentId;
|
||||
|
||||
|
||||
@ -39,10 +39,6 @@ public class EbikeRefund implements Serializable {
|
||||
*/
|
||||
private String orderId;
|
||||
|
||||
/**
|
||||
* 支付记录id
|
||||
*/
|
||||
private String recordId;
|
||||
|
||||
/**
|
||||
* 微信支付订单号
|
||||
@ -76,7 +72,7 @@ public class EbikeRefund implements Serializable {
|
||||
private Double refund;
|
||||
|
||||
/**
|
||||
* 退款总金额
|
||||
* 原订单金额
|
||||
*/
|
||||
private Double total;
|
||||
|
||||
|
||||
@ -27,27 +27,36 @@ public interface WxPayService {
|
||||
/**
|
||||
* JSAPI支付下单
|
||||
*
|
||||
* @param outTradeNo 订单id
|
||||
* @param orderId 订单id
|
||||
* @return 下单成功返回wx支付请求参数,否则返回null
|
||||
*/
|
||||
JSONObject prepay(String outTradeNo);
|
||||
JSONObject prepay(String orderId);
|
||||
|
||||
|
||||
/**
|
||||
* 通过支付订单号查询支付订单
|
||||
*
|
||||
* @param outTradeNo 支付订单号
|
||||
* @return 支付订单信息
|
||||
*/
|
||||
Transaction queryOrderByOutTradeNo(String outTradeNo);
|
||||
|
||||
|
||||
/**
|
||||
* 通过商户(骑行)订单号查询支付订单
|
||||
*
|
||||
* @param outTradeNo 商户(骑行)订单号
|
||||
* @param orderId 商户(骑行)订单号
|
||||
* @return 支付订单信息
|
||||
*/
|
||||
Transaction queryOrderByOutTradeNo(String outTradeNo);
|
||||
Transaction queryOrderByOrderId(String orderId);
|
||||
|
||||
/**
|
||||
* 通过订单号查询支付订单状态
|
||||
*
|
||||
* @param outTradeNo 商户(骑行)订单号
|
||||
* @param orderId 商户(骑行)订单号
|
||||
* @return 支付订单信息
|
||||
*/
|
||||
HandleNotifyResult queryOrderStatusByOutTradeNo(String outTradeNo);
|
||||
HandleNotifyResult queryOrderStatusByOrderId(String orderId);
|
||||
|
||||
/**
|
||||
* 处理支付回调
|
||||
|
||||
@ -4,8 +4,6 @@ import com.cdzy.payment.model.enums.PayMethod;
|
||||
import com.cdzy.payment.utils.StringUtils;
|
||||
import com.ebike.feign.clients.OrdersFeignClient;
|
||||
import com.ebike.feign.model.res.ResFeignOrderPaymentDto;
|
||||
import com.mybatisflex.core.query.QueryColumn;
|
||||
import com.mybatisflex.core.query.QueryMethods;
|
||||
import com.mybatisflex.core.query.QueryWrapper;
|
||||
import com.mybatisflex.spring.service.impl.ServiceImpl;
|
||||
import com.cdzy.payment.model.entity.EbikePayment;
|
||||
@ -18,6 +16,7 @@ import org.springframework.stereotype.Service;
|
||||
import java.util.List;
|
||||
|
||||
import static com.cdzy.payment.model.entity.table.EbikePaymentTableDef.EBIKE_PAYMENT;
|
||||
import static com.mybatisflex.core.constant.FuncName.*;
|
||||
|
||||
/**
|
||||
* 用户订单支付记录 服务层实现。
|
||||
@ -33,27 +32,29 @@ public class EbikePaymentServiceImpl extends ServiceImpl<EbikePaymentMapper, Ebi
|
||||
|
||||
@Override
|
||||
public List<EbikePayment> getNoPayOrderByDuration(int duration) {
|
||||
QueryColumn time = QueryMethods.secToTime(String.valueOf(duration * 60));
|
||||
// trade_state 等于 NOTPAY未支付的, 并且创建时间未超过duration分钟的订单
|
||||
String timeFilter = String.format("%s(%s, %s(%s))<%s()", ADDTIME, EBIKE_PAYMENT.CREATE_TIME.getName(), SEC_TO_TIME
|
||||
, String.valueOf(duration * 60), NOW);
|
||||
QueryWrapper query = QueryWrapper.create()
|
||||
.where(EBIKE_PAYMENT.TRADE_STATE.eq(Transaction.TradeStateEnum.NOTPAY.ordinal()))
|
||||
.and(QueryMethods.addTime(EBIKE_PAYMENT.CREATE_TIME, time).lt(QueryMethods.now()));
|
||||
.and(timeFilter);
|
||||
return list(query);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<EbikePayment> getExpireOrderByDuration(int duration) {
|
||||
QueryColumn time = QueryMethods.secToTime(String.valueOf(duration * 60));
|
||||
// trade_state 等于 NOTPAY未支付的, 并且创建时间超过duration分钟的订单
|
||||
String timeFilter = String.format("%s(%s, %s(%s))>=%s()", ADDTIME, EBIKE_PAYMENT.CREATE_TIME.getName(), SEC_TO_TIME
|
||||
, String.valueOf(duration * 60), NOW);
|
||||
QueryWrapper query = QueryWrapper.create()
|
||||
.where(EBIKE_PAYMENT.TRADE_STATE.eq(Transaction.TradeStateEnum.NOTPAY.ordinal()))
|
||||
.and(QueryMethods.addTime(EBIKE_PAYMENT.CREATE_TIME, time).ge(QueryMethods.now()));
|
||||
.and(timeFilter);
|
||||
return list(query);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Boolean updatePaymentStatus(Transaction transaction) {
|
||||
EbikePayment ebikePayment = new EbikePayment();
|
||||
EbikePayment ebikePayment = getByPaymentId(transaction.getOutTradeNo());
|
||||
//ebikePayment.setRecordId(recordId);
|
||||
ebikePayment.setTradeState(String.valueOf(transaction.getTradeState().ordinal()));
|
||||
if (Transaction.TradeStateEnum.SUCCESS.equals(transaction.getTradeState())) {
|
||||
@ -65,14 +66,12 @@ public class EbikePaymentServiceImpl extends ServiceImpl<EbikePaymentMapper, Ebi
|
||||
ebikePayment.setTransactionId(transaction.getTransactionId());
|
||||
// 同步支付状态
|
||||
ResFeignOrderPaymentDto paymentParam = new ResFeignOrderPaymentDto();
|
||||
paymentParam.setOrderId(Long.valueOf(transaction.getOutTradeNo()));
|
||||
paymentParam.setOrderId(Long.valueOf(ebikePayment.getOrderId()));
|
||||
paymentParam.setPaymentTime(ebikePayment.getPaymentTime());
|
||||
paymentParam.setPaymentMethod(PayMethod.wechat.name());
|
||||
ordersFeignClient.payment(paymentParam);
|
||||
}
|
||||
QueryWrapper query = QueryWrapper.create()
|
||||
.where(EBIKE_PAYMENT.ORDER_ID.eq(transaction.getOutTradeNo()));
|
||||
return update(ebikePayment, query);
|
||||
return updateById(ebikePayment);
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -81,4 +80,16 @@ public class EbikePaymentServiceImpl extends ServiceImpl<EbikePaymentMapper, Ebi
|
||||
.where(EBIKE_PAYMENT.ORDER_ID.eq(orderId));
|
||||
return this.getOne(query);
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据支付id查询支付记录
|
||||
*
|
||||
* @param paymentId 支付id
|
||||
* @return
|
||||
*/
|
||||
private EbikePayment getByPaymentId(String paymentId) {
|
||||
QueryWrapper query = QueryWrapper.create()
|
||||
.where(EBIKE_PAYMENT.PAYMENT_ID.eq(paymentId));
|
||||
return this.getOne(query);
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,13 +1,11 @@
|
||||
package com.cdzy.payment.service.impl;
|
||||
|
||||
import com.ebike.feign.clients.OrdersFeignClient;
|
||||
import com.mybatisflex.core.query.QueryMethods;
|
||||
import com.mybatisflex.core.query.QueryWrapper;
|
||||
import com.mybatisflex.spring.service.impl.ServiceImpl;
|
||||
import com.cdzy.payment.model.entity.EbikeRefund;
|
||||
import com.cdzy.payment.mapper.EbikeRefundMapper;
|
||||
import com.cdzy.payment.service.EbikeRefundService;
|
||||
import com.wechat.pay.java.service.payments.model.Transaction;
|
||||
import com.wechat.pay.java.service.refund.model.Refund;
|
||||
import com.wechat.pay.java.service.refund.model.Status;
|
||||
import jakarta.annotation.Resource;
|
||||
@ -17,6 +15,7 @@ import java.time.LocalDateTime;
|
||||
import java.util.List;
|
||||
|
||||
import static com.cdzy.payment.model.entity.table.EbikeRefundTableDef.EBIKE_REFUND;
|
||||
import static com.mybatisflex.core.constant.FuncName.*;
|
||||
|
||||
/**
|
||||
* 用户订单退款记录 服务层实现。
|
||||
@ -41,10 +40,12 @@ public class EbikeRefundServiceImpl extends ServiceImpl<EbikeRefundMapper, Ebike
|
||||
|
||||
@Override
|
||||
public List<EbikeRefund> getNoSuccessRefundOrderByDuration(int duration) {
|
||||
// trade_state 不等于 SUCCESS退款成功的, 并且创建时间超过duration分钟的订单
|
||||
// trade_state 等于 PROCESSING正在退款中的, 并且创建时间超过duration分钟的订单
|
||||
String timeFilter = String.format("%s(%s, %s(%s))>=%s()", ADDTIME, EBIKE_REFUND.CREATE_TIME.getName(), SEC_TO_TIME
|
||||
, String.valueOf(duration * 60), NOW);
|
||||
QueryWrapper query = QueryWrapper.create()
|
||||
.where(EBIKE_REFUND.STATUS.eq(Status.PROCESSING.ordinal()))
|
||||
.and(QueryMethods.addTime(EBIKE_REFUND.CREATE_TIME, QueryMethods.secToTime(String.valueOf(duration * 60))).ge(QueryMethods.now()));
|
||||
.and(timeFilter);
|
||||
return list(query);
|
||||
}
|
||||
|
||||
|
||||
@ -18,7 +18,7 @@ import com.ebike.feign.model.rsp.AmountDto;
|
||||
import com.ebike.feign.model.rsp.DetailDto;
|
||||
import com.ebike.feign.model.rsp.EbikePaymentDto;
|
||||
import com.wechat.pay.java.core.Config;
|
||||
import com.wechat.pay.java.core.cipher.RSASigner;
|
||||
import com.wechat.pay.java.core.cipher.Signer;
|
||||
import com.wechat.pay.java.core.exception.HttpException;
|
||||
import com.wechat.pay.java.core.exception.MalformedMessageException;
|
||||
import com.wechat.pay.java.core.exception.ServiceException;
|
||||
@ -41,6 +41,8 @@ import org.springframework.stereotype.Service;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import java.math.BigDecimal;
|
||||
import java.time.*;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import static com.wechat.pay.java.core.http.Constant.*;
|
||||
import static com.wechat.pay.java.core.http.Constant.WECHAT_PAY_SERIAL;
|
||||
@ -63,7 +65,7 @@ public class WxPayServiceImpl implements WxPayService {
|
||||
@Resource
|
||||
private WxPayConfig wxPayConfig;
|
||||
@Resource
|
||||
private RSASigner wxRsaSigner;
|
||||
private Signer wxRsaSigner;
|
||||
@Resource
|
||||
private Config certificateConfig;
|
||||
@Resource
|
||||
@ -71,13 +73,14 @@ public class WxPayServiceImpl implements WxPayService {
|
||||
@Resource
|
||||
private EbikeRefundService ebikeRefundService;
|
||||
@Resource
|
||||
private OrdersFeignClient orderFeingClient;
|
||||
private OrdersFeignClient ordersFeignClient;
|
||||
|
||||
@Override
|
||||
public boolean closeOrder(String outTradeNo) {
|
||||
try {
|
||||
CloseOrderRequest request = new CloseOrderRequest();
|
||||
request.setOutTradeNo(outTradeNo);
|
||||
request.setMchid(wxPayConfig.getMerchantId());
|
||||
wxJsapiService.closeOrder(request);
|
||||
log.info("关闭订单成功,订单号:{}", outTradeNo);
|
||||
// ebikePaymentService.updatePaymentStatus(outTradeNo, 2);
|
||||
@ -90,27 +93,42 @@ public class WxPayServiceImpl implements WxPayService {
|
||||
|
||||
|
||||
@Override
|
||||
public JSONObject prepay(String outTradeNo){
|
||||
public JSONObject prepay(String orderId){
|
||||
JSONObject r = new JSONObject();
|
||||
// 首先检查订单是否正在付中、或者已经支付成功
|
||||
EbikePayment ebikePayment = ebikePaymentService.getByOrderId(outTradeNo);
|
||||
// 关闭了的订单,重新发起请求
|
||||
EbikePayment ebikePayment = ebikePaymentService.getByOrderId(orderId);
|
||||
if (ebikePayment != null) {
|
||||
if (String.valueOf(Transaction.TradeStateEnum.SUCCESS.ordinal()).equals(ebikePayment.getTradeState())) {
|
||||
log.info("订单已经支付成功,订单号:{}", outTradeNo);
|
||||
String tradeState = ebikePayment.getTradeState();
|
||||
if (String.valueOf(Transaction.TradeStateEnum.SUCCESS.ordinal()).equals(tradeState)) {
|
||||
log.info("订单已经支付成功,订单号:{}", orderId);
|
||||
r.put("error", "订单已经支付成功");
|
||||
return r;
|
||||
}
|
||||
if (String.valueOf(Transaction.TradeStateEnum.NOTPAY.ordinal()).equals(ebikePayment.getTradeState())
|
||||
||String.valueOf(Transaction.TradeStateEnum.USERPAYING.ordinal()).equals(ebikePayment.getTradeState())) {
|
||||
log.info("订单正在支付中,订单号:{}", outTradeNo);
|
||||
r.put("error", "订单正在支付中");
|
||||
return null;
|
||||
if (String.valueOf(Transaction.TradeStateEnum.NOTPAY.ordinal()).equals(tradeState)
|
||||
||String.valueOf(Transaction.TradeStateEnum.USERPAYING.ordinal()).equals(tradeState)) {
|
||||
// 检查订单是否关闭
|
||||
Transaction t = queryOrderByOutTradeNo(ebikePayment.getPaymentId());
|
||||
if (t != null && Transaction.TradeStateEnum.CLOSED.equals(t.getTradeState())) {
|
||||
log.info("订单已经关闭,订单号:{}, 重新发起请求", orderId);
|
||||
ebikePayment.setTradeState(String.valueOf(Transaction.TradeStateEnum.CLOSED.ordinal()));
|
||||
ebikePayment.setPaymentId(StringUtils.generateSnowflakeId("paymentId"));
|
||||
}else{
|
||||
log.info("订单正在支付中,订单号:{}", orderId);
|
||||
}
|
||||
} else if (String.valueOf(Transaction.TradeStateEnum.CLOSED.ordinal()).equals(tradeState)) {
|
||||
log.info("订单已经关闭,订单号:{}, 重新发起请求", orderId);
|
||||
ebikePayment.setPaymentId(StringUtils.generateSnowflakeId("paymentId"));
|
||||
}else {
|
||||
log.info("订单状态异常,订单号:{}", orderId);
|
||||
r.put("error", "订单状态异常: ");
|
||||
return r;
|
||||
}
|
||||
}
|
||||
//查询订单, orderFeingClient.getOrderById(orderId)
|
||||
JsonResult<?> result = orderFeingClient.getPaymentDetails(Long.valueOf(outTradeNo));
|
||||
JsonResult<?> result = ordersFeignClient.getPaymentDetails(Long.valueOf(orderId));
|
||||
if (result.getCode() != 200) {
|
||||
log.error("查询订单 {} 失败, {}", outTradeNo, result.getMessage());
|
||||
log.error("查询订单 {} 失败, {}", orderId, result.getMessage());
|
||||
r.put("error", "查询订单失败, "+result.getMessage());
|
||||
return r;
|
||||
}
|
||||
@ -127,18 +145,20 @@ public class WxPayServiceImpl implements WxPayService {
|
||||
* @return 下单成功返回wx支付请求参数,否则返回null
|
||||
*/
|
||||
private JSONObject prepay(EbikePaymentDto paymentDto, EbikePayment ebikePayment) {
|
||||
JSONObject r = new JSONObject();
|
||||
String outTradeNo = paymentDto.getOrderId();
|
||||
String description = paymentDto.getDescription();
|
||||
String goodsTag = paymentDto.getGoodsTag();
|
||||
String openId = paymentDto.getOpenId();
|
||||
AmountDto amount = paymentDto.getAmount();
|
||||
DetailDto detail = paymentDto.getDetail();
|
||||
String payId = ebikePayment==null?outTradeNo : ebikePayment.getPaymentId();
|
||||
try {
|
||||
PrepayRequest request = new PrepayRequest();
|
||||
request.setAppid(wxPayConfig.getAppId());
|
||||
request.setMchid(wxPayConfig.getMerchantId());
|
||||
request.setDescription(description);
|
||||
request.setOutTradeNo(outTradeNo);
|
||||
request.setOutTradeNo(payId);
|
||||
request.setNotifyUrl(wxPayConfig.getPayNotifyUrl());
|
||||
LocalDateTime expireTime = LocalDateTime.now().plusMinutes(wxPayConfig.getExpireMinute());
|
||||
request.setTimeExpire(StringUtils.formatLocalDatetime(expireTime));
|
||||
@ -151,22 +171,36 @@ public class WxPayServiceImpl implements WxPayService {
|
||||
payer.setOpenid(openId);
|
||||
request.setPayer(payer);
|
||||
Detail detailReq = new Detail();
|
||||
detailReq.setGoodsDetail(detail.getGoodsDetail().stream().map(goodsDetail -> {
|
||||
List<GoodsDetail> goodsDetails = detail.getGoodsDetail().stream().map(goodsDetail -> {
|
||||
GoodsDetail goodsDetailReq = new GoodsDetail();
|
||||
goodsDetailReq.setGoodsName(goodsDetail.getItemName());
|
||||
goodsDetailReq.setMerchantGoodsId(goodsDetail.getItemId());
|
||||
goodsDetailReq.setQuantity(goodsDetail.getQuantity());
|
||||
goodsDetailReq.setUnitPrice(BigDecimal.valueOf(goodsDetail.getUnitPrice()*100.0).intValue());
|
||||
return goodsDetailReq;
|
||||
}).toList());
|
||||
}).toList();
|
||||
if (goodsDetails.isEmpty()){
|
||||
goodsDetails = new ArrayList<>();
|
||||
GoodsDetail goodsDetail = new GoodsDetail();
|
||||
String snowId = StringUtils.generateSnowflakeId("goodsId");
|
||||
goodsDetail.setMerchantGoodsId(snowId);
|
||||
goodsDetail.setGoodsName(goodsTag);
|
||||
goodsDetail.setQuantity(1);
|
||||
goodsDetail.setUnitPrice(BigDecimal.valueOf(amount.getTotal()*100.0).intValue());
|
||||
goodsDetails.add(goodsDetail);
|
||||
}
|
||||
detailReq.setGoodsDetail(goodsDetails);
|
||||
detailReq.setCostPrice(BigDecimal.valueOf(detail.getCostPrice()*100.0).intValue());
|
||||
detailReq.setInvoiceId(detail.getInvoiceId());
|
||||
request.setDetail(detailReq);
|
||||
|
||||
SettleInfo settleInfo = new SettleInfo();
|
||||
settleInfo.setProfitSharing(false);
|
||||
request.setSettleInfo(settleInfo);
|
||||
//log.info("微信支付下单prepay,订单号:{}, {}", outTradeNo, JSONObject.toJSONString(request));
|
||||
PrepayResponse response = wxJsapiService.prepay(request);
|
||||
String payId = response.getPrepayId();
|
||||
//入库, 重新发起支付更新记录(订单号<-->记录号一一对应)
|
||||
if (payId != null) {
|
||||
if (response != null && response.getPrepayId() != null) {
|
||||
log.info("微信支付下单prepay成功,支付订单号:{}", response.getPrepayId());
|
||||
if (ebikePayment == null) {
|
||||
ebikePayment = new EbikePayment();
|
||||
ebikePayment.setOrderId(outTradeNo);
|
||||
@ -189,14 +223,16 @@ public class WxPayServiceImpl implements WxPayService {
|
||||
wxJsapiPromptDto.setAppId(wxPayConfig.getAppId());
|
||||
wxJsapiPromptDto.setTimeStamp(String.valueOf(Instant.now().getEpochSecond()));
|
||||
wxJsapiPromptDto.setNonceStr(NonceUtil.createNonce(32));
|
||||
wxJsapiPromptDto.setExtension("prepay_id=" + payId);
|
||||
wxJsapiPromptDto.setExtension("prepay_id=" + response.getPrepayId());
|
||||
return wxJsapiPromptDto.toJson(wxRsaSigner);
|
||||
}
|
||||
log.error("微信支付下单prepay失败,订单号:{}", outTradeNo);
|
||||
return null;
|
||||
r.put("error", "微信支付下单prepay失败");
|
||||
return r;
|
||||
}catch (Exception e) {
|
||||
logError("微信支付下单prepay", e);
|
||||
return null;
|
||||
r.put("error", "微信支付下单prepay失败: "+e.getMessage());
|
||||
return r;
|
||||
}
|
||||
}
|
||||
|
||||
@ -209,13 +245,23 @@ public class WxPayServiceImpl implements WxPayService {
|
||||
}
|
||||
|
||||
@Override
|
||||
public HandleNotifyResult queryOrderStatusByOutTradeNo(String outTradeNo) {
|
||||
public Transaction queryOrderByOrderId(String orderId) {
|
||||
EbikePayment ebikePayment = ebikePaymentService.getByOrderId(orderId);
|
||||
if (ebikePayment==null){
|
||||
log.error("{}支付订单不存在", orderId);
|
||||
return null;
|
||||
}
|
||||
return queryOrderByOutTradeNo(ebikePayment.getPaymentId());
|
||||
}
|
||||
|
||||
@Override
|
||||
public HandleNotifyResult queryOrderStatusByOrderId(String orderId) {
|
||||
// 先查本地数据库,如果退款状态不为SUCCESS,需要查询微信支付
|
||||
HandleNotifyResult result = new HandleNotifyResult();
|
||||
EbikePayment ebikePayment = ebikePaymentService.getByOrderId(outTradeNo);
|
||||
EbikePayment ebikePayment = ebikePaymentService.getByOrderId(orderId);
|
||||
if (ebikePayment==null){
|
||||
log.error("{}支付订单不存在", outTradeNo);
|
||||
result.setMessage(String.format("{%s}支付订单不存在", outTradeNo));
|
||||
log.error("{}支付订单不存在", orderId);
|
||||
result.setMessage(String.format("{%s}支付订单不存在", orderId));
|
||||
return result;
|
||||
}
|
||||
result.setSuccess(String.valueOf(Transaction.TradeStateEnum.SUCCESS.ordinal()).equals(ebikePayment.getTradeState()));
|
||||
@ -223,11 +269,9 @@ public class WxPayServiceImpl implements WxPayService {
|
||||
result.setMessage(String.format("订单%s支付成功", ebikePayment.getOrderId()));
|
||||
return result;
|
||||
}
|
||||
QueryOrderByOutTradeNoRequest request = new QueryOrderByOutTradeNoRequest();
|
||||
request.setOutTradeNo(outTradeNo);
|
||||
request.setMchid(wxPayConfig.getMerchantId());
|
||||
Transaction r = wxJsapiService.queryOrderByOutTradeNo(request);
|
||||
if(r!=null&& r.getTradeState().equals(Transaction.TradeStateEnum.SUCCESS)) {
|
||||
|
||||
Transaction r =queryOrderByOutTradeNo(ebikePayment.getPaymentId());
|
||||
if(r!=null&& Transaction.TradeStateEnum.SUCCESS.equals(r.getTradeState())) {
|
||||
result.setMessage(String.format("订单%s支付成功", ebikePayment.getOrderId()));
|
||||
result.setSuccess(true);
|
||||
// 更新支付状态
|
||||
@ -295,6 +339,7 @@ public class WxPayServiceImpl implements WxPayService {
|
||||
ebikeRefund.setCreateTime(LocalDateTime.now());
|
||||
ebikeRefund.setRefundId(outRefundNo);
|
||||
ebikeRefund.setOrderId(outTradeNo);
|
||||
ebikeRefund.setTotal(ebikePayment.getTotal());
|
||||
ebikeRefund.setTransactionId(transactionId);
|
||||
ebikeRefund.setReason(reason);
|
||||
ebikeRefund.setStatus(String.valueOf(Status.PROCESSING.ordinal()));
|
||||
|
||||
@ -1,5 +1,6 @@
|
||||
package com.cdzy.payment.task;
|
||||
|
||||
import com.cdzy.payment.config.WxPayConfig;
|
||||
import jakarta.annotation.PostConstruct;
|
||||
import jakarta.annotation.Resource;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
@ -17,17 +18,18 @@ import org.springframework.stereotype.Component;
|
||||
@Slf4j
|
||||
@Component
|
||||
public class ScheduledTaskManager {
|
||||
// 每隔30秒执行1次
|
||||
private final static String CRON_EXPRESSION = "0/30 * * * *?";
|
||||
|
||||
// @Scheduled任务线程默认串行执行,需要考虑并发问题
|
||||
@Resource
|
||||
private WxPayConfig wxPayConfig;
|
||||
@Resource
|
||||
private ThreadPoolTaskScheduler threadPoolTaskScheduler;
|
||||
@Resource
|
||||
private WsPayTask wxPayTask;
|
||||
|
||||
@PostConstruct
|
||||
public void init() {
|
||||
String CRON_EXPRESSION = wxPayConfig.getCronExpression();
|
||||
// 启动定时任务
|
||||
// 1. 每隔30秒执行1次,查询创建未超过5分钟,并且未支付的订单
|
||||
threadPoolTaskScheduler.schedule(new Runnable() {
|
||||
@ -41,17 +43,18 @@ public class ScheduledTaskManager {
|
||||
}
|
||||
}, new CronTrigger(CRON_EXPRESSION));
|
||||
|
||||
// 2. 每隔30秒执行1次,查询创建超过5分钟,并且未支付的订单
|
||||
threadPoolTaskScheduler.schedule(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
try {
|
||||
wxPayTask.closeOrder();
|
||||
} catch (Exception e) {
|
||||
log.error("closeOrder 执行异常", e);
|
||||
}
|
||||
}
|
||||
}, new CronTrigger(CRON_EXPRESSION));
|
||||
//========支付系统自动关闭,不主动关闭,每次发起请求的时候检测是否关闭========
|
||||
//// 2. 每隔30秒执行1次,查询创建超过5分钟,并且未支付的订单
|
||||
//threadPoolTaskScheduler.schedule(new Runnable() {
|
||||
// @Override
|
||||
// public void run() {
|
||||
// try {
|
||||
// wxPayTask.closeOrder();
|
||||
// } catch (Exception e) {
|
||||
// log.error("closeOrder 执行异常", e);
|
||||
// }
|
||||
// }
|
||||
//}, new CronTrigger(CRON_EXPRESSION));
|
||||
|
||||
// 3. 每隔30秒执行1次,查询创建未超过5分钟,并且未成功的退款单
|
||||
threadPoolTaskScheduler.schedule(new Runnable() {
|
||||
|
||||
@ -36,7 +36,7 @@ public class WsPayTask {
|
||||
|
||||
|
||||
/**
|
||||
* 查询创建未超过5分钟,并且未支付的订单
|
||||
* 查询创建未超过24小时,并且未支付的订单
|
||||
*/
|
||||
public void checkOrderStatus() throws Exception {
|
||||
log.info("checkOrderStatus 执行......");
|
||||
@ -54,7 +54,7 @@ public class WsPayTask {
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询创建超过5分钟,并且未支付的订单
|
||||
* 查询创建超过24小时,并且未支付的订单
|
||||
*/
|
||||
public void closeOrder() throws Exception {
|
||||
log.info("closeOrder 执行......");
|
||||
@ -76,7 +76,7 @@ public class WsPayTask {
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询创建未超过5分钟,并且未成功的退款单
|
||||
* 查询创建未超过24小时,并且未成功的退款单
|
||||
*/
|
||||
public void checkRefundStatus() throws Exception {
|
||||
log.info("checkRefundStatus 执行......");
|
||||
|
||||
@ -36,13 +36,14 @@ payment:
|
||||
app-id: wx327d788d7bd6eddf
|
||||
merchant-id: 1715147005
|
||||
private-key-path: D:/Projects/eBIKE/docs/secrets/apiclient_key.pem
|
||||
public-key-path: D:/Projects/eBIKE/docs/secrets/apiclient_cert.pem
|
||||
public-key-path: D:/Projects/eBIKE/docs/secrets/apiclient_pubkey.pem
|
||||
merchant-serial-number: 7873E3E694ADD0368EA3E9FAC929F496EECB8DF9
|
||||
api-v3-key: 1715147005V3Key20250425174554633
|
||||
public-key-id: PUB_KEY_ID_0117151470052025042500331704000601
|
||||
pay-notify_url: http://192.168.2.156:10017/wxPayment/pay-notify
|
||||
refund-notify_url: http://192.168.2.156:10017/wxPayment/refund-notify
|
||||
expire-minutes: 5
|
||||
expire-minutes: 1440
|
||||
cron-expression: 0 0 0,12 * * ?
|
||||
task-scheduler-pool:
|
||||
poolSize: 100
|
||||
threadNamePrefix: task-scheduled-
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user