This commit is contained in:
dzl 2025-05-09 17:55:29 +08:00
commit deded23732
8 changed files with 119 additions and 118 deletions

View File

@ -2,7 +2,6 @@ package com.cdzy.payment.controller;
import com.alibaba.fastjson2.JSONObject;
import com.cdzy.common.model.JsonResult;
import com.cdzy.payment.model.dto.EbikePaymentDto;
import com.cdzy.payment.model.dto.EbikeRefundDto;
import com.cdzy.payment.model.dto.HandleNotifyResult;
import com.cdzy.payment.service.WxPayService;
@ -10,12 +9,7 @@ import com.wechat.pay.java.service.payments.model.Transaction;
import com.wechat.pay.java.service.refund.model.Refund;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.bind.annotation.*;
/**
* 用户订单微信支付 控制层
@ -34,48 +28,36 @@ public class EbikeWxPaymentController {
/**
* 微信支付下单
*
* @param paymentDto 支付信息
* @param orderId 骑行订单id
* @return 下单成功返回true否则返回false
*/
@PostMapping("/prepay")
public JsonResult<?> prepay(@RequestBody EbikePaymentDto paymentDto) {
JSONObject r = wxPayService.prepay(paymentDto.getOrderId(), paymentDto.getDescription(), paymentDto.getGoodsTag(), paymentDto.getOpenId(), paymentDto.getAmount(), paymentDto.getDetail(), paymentDto.getClientIp());
public JsonResult<?> prepay(@RequestParam(name = "orderId") String orderId) {
JSONObject r = wxPayService.prepay(orderId);
return r == null?JsonResult.failed("下单失败"):JsonResult.success(r);
}
/**
* 通过交易订单号查询支付订单
*
* @param transactionId 微信支付订单号
* @return 支付订单信息
*/
@GetMapping("/queryOrderById/{transactionId}")
public JsonResult<?> queryOrderById(@PathVariable String transactionId) {
Transaction r = wxPayService.queryOrderById(transactionId);
return r == null?JsonResult.failed(String.format("交易订单号{%s}查询支付订单失败", transactionId)):JsonResult.success(r);
}
/**
* 通过商户(骑行)订单号查询支付订单
*
* @param outTradeNo 商户(骑行)订单号
* @param orderId 商户(骑行)订单号
* @return 支付订单信息
*/
@GetMapping("/queryOrderByOutTradeNo/{outTradeNo}")
public JsonResult<?> queryOrderByOutTradeNo(@PathVariable String outTradeNo) {
Transaction r = wxPayService.queryOrderByOutTradeNo(outTradeNo);
return r == null?JsonResult.failed(String.format("骑行订单号{%s}查询支付订单失败", outTradeNo)):JsonResult.success(r);
@GetMapping("/queryOrder/{orderId}")
public JsonResult<?> queryOrderByOutTradeNo(@PathVariable String orderId) {
Transaction r = wxPayService.queryOrderByOutTradeNo(orderId);
return r == null?JsonResult.failed(String.format("骑行订单号{%s}查询支付订单失败", orderId)):JsonResult.success(r);
}
/**
* 通过交易订单号查询支付订单状态
* 通过商户(骑行)订单订单号查询支付订单状态
*
* @param transactionId 微信支付订单号
* @return 支付订单信息
* @param orderId 微信支付订单号
* @return 订单信息支付状态
*/
@GetMapping("/queryOrderStatusById/{transactionId}")
public JsonResult<?> queryOrderStatusById(@PathVariable String transactionId) {
HandleNotifyResult r = wxPayService.queryOrderStatusById(transactionId);
@GetMapping("/queryOrderStatus/{orderId}")
public JsonResult<?> queryOrderStatusById(@PathVariable String orderId) {
HandleNotifyResult r = wxPayService.queryOrderStatusByOutTradeNo(orderId);
return JsonResult.success(r);
}
@ -87,20 +69,20 @@ public class EbikeWxPaymentController {
*/
@PostMapping("/refund")
public JsonResult<?> refund(@RequestBody EbikeRefundDto refundDto) {
String r = wxPayService.refund(refundDto.getPaymentId(), refundDto.getOrderId(), refundDto.getReason(), refundDto.getAmount());
String r = wxPayService.refund(refundDto.getOrderId(), refundDto.getReason());
return r == null?JsonResult.failed("退款失败"):JsonResult.success(r);
}
/**
* 通过退款单号查询退款信息
*
* @param outRefundNo 商户(骑行)退款单号
* @param refundId 商户(骑行)退款单号
* @return 退款信息
*/
@GetMapping("/queryRefund/{outRefundNo}")
public JsonResult<?> refundQuery(@PathVariable String outRefundNo) {
Refund r = wxPayService.queryRefundByOutNo(outRefundNo);
return r == null?JsonResult.failed(String.format("退款单号{%s}查询退款失败", outRefundNo)):JsonResult.success(r);
@GetMapping("/queryRefund/{refundId}")
public JsonResult<?> refundQuery(@PathVariable String refundId) {
Refund r = wxPayService.queryRefundByOutNo(refundId);
return r == null?JsonResult.failed(String.format("退款单号{%s}查询退款失败", refundId)):JsonResult.success(r);
}
}

View File

@ -1,8 +1,6 @@
package com.cdzy.payment.model.dto;
import com.wechat.pay.java.service.payments.jsapi.model.Amount;
import com.wechat.pay.java.service.payments.jsapi.model.Detail;
import com.wechat.pay.java.service.refund.model.AmountReq;
import jakarta.validation.constraints.NotBlank;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
@ -21,18 +19,12 @@ public class EbikeRefundDto {
/**
* 商户(骑行)订单号
*/
@NotBlank(message = "订单id不能为空")
private String orderId;
/**
* 支付交易会话标识
*/
private String paymentId;
/**
* 退款原因
*/;
private String reason;
/**
* 金额
*/
private AmountRefundDto amount;
@NotBlank(message = "退款原因不能为空")
private String reason;
}

View File

@ -40,10 +40,15 @@ public class EbikePayment implements Serializable {
private String orderId;
/**
* 支付交易会话标识;有效期为2小时
* 支付交易会话标识;有效期为2小时
*/
private String paymentId;
/**
* 微信支付订单号
*/
private String transactionId;
/**
* 提交时间
*/

View File

@ -3,7 +3,6 @@ package com.cdzy.payment.model.entity;
import com.mybatisflex.annotation.Id;
import com.mybatisflex.annotation.Table;
import java.io.Serializable;
import java.math.BigDecimal;
import java.io.Serial;
import java.time.LocalDateTime;
@ -46,9 +45,9 @@ public class EbikeRefund implements Serializable {
private String recordId;
/**
* 支付交易会话标识;有效期为2小时
* 微信支付订单号
*/
private String paymentId;
private String transactionId;
/**
* 提交时间

View File

@ -38,10 +38,10 @@ public interface EbikePaymentService extends IService<EbikePayment> {
Boolean updatePaymentStatus(Transaction transaction);
/**
* 根据支付订单id查询支付记录
* 根据订单id查询支付记录
*
* @param paymentId 支付订单id
* @param orderId 订单id
* @return
*/
EbikePayment getByPaymentId(String paymentId);
EbikePayment getByOrderId(String orderId);
}

View File

@ -2,9 +2,7 @@ package com.cdzy.payment.service;
import com.alibaba.fastjson2.JSONObject;
import com.cdzy.payment.model.dto.AmountDto;
import com.cdzy.payment.model.dto.AmountRefundDto;
import com.cdzy.payment.model.dto.DetailDto;
import com.cdzy.payment.model.dto.HandleNotifyResult;
import com.wechat.pay.java.service.payments.model.Transaction;
import com.wechat.pay.java.service.refund.model.Refund;
@ -30,23 +28,11 @@ public interface WxPayService {
/**
* JSAPI支付下单
*
* @param outTradeNo 商户(骑行)订单号
* @param description 商品描述
* @param goodsTag 商品标记
* @param openId 用户标识
* @param amount 金额
* @param detail 商品详情
* @param clientIp 客户端IP
* @param outTradeNo 订单id
* @return 下单成功返回true否则返回false
*/
JSONObject prepay(String outTradeNo, String description, String goodsTag, String openId, AmountDto amount, DetailDto detail, String clientIp);
/**
* 通过交易订单号查询支付订单
*
* @param transactionId 微信支付订单号
* @return 支付订单信息
*/
Transaction queryOrderById(String transactionId);
JSONObject prepay(String outTradeNo);
/**
* 通过商户(骑行)订单号查询支付订单
@ -57,12 +43,12 @@ public interface WxPayService {
Transaction queryOrderByOutTradeNo(String outTradeNo);
/**
* 通过交易订单号查询支付订单状态
* 通过订单号查询支付订单状态
*
* @param transactionId 微信支付订单号
* @param outTradeNo 商户(骑行)订单号
* @return 支付订单信息
*/
HandleNotifyResult queryOrderStatusById(String transactionId);
HandleNotifyResult queryOrderStatusByOutTradeNo(String outTradeNo);
/**
* 处理支付回调
@ -75,13 +61,11 @@ public interface WxPayService {
/**
* 退款申请
*
* @param transactionId 微信支付订单号
* @param outTradeNo 商户(骑行)订单号
* @param reason 退款原因
* @param amount 退款金额
* @return 退款信息id
*/
String refund(String transactionId, String outTradeNo, String reason, AmountRefundDto amount);
String refund(String outTradeNo, String reason);
/**

View File

@ -34,9 +34,9 @@ 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分钟的订单
// trade_state 等于 NOTPAY未支付的 USERPAYING正在支持的 并且创建时间未超过duration分钟的订单
QueryWrapper query = QueryWrapper.create()
.where(EBIKE_PAYMENT.TRADE_STATE.eq(Transaction.TradeStateEnum.USERPAYING.ordinal()))
.where(EBIKE_PAYMENT.TRADE_STATE.eq(Transaction.TradeStateEnum.NOTPAY.ordinal()))
.and(QueryMethods.addTime(EBIKE_PAYMENT.CREATE_TIME, time).lt(QueryMethods.now()));
return list(query);
}
@ -44,9 +44,9 @@ public class EbikePaymentServiceImpl extends ServiceImpl<EbikePaymentMapper, Ebi
@Override
public List<EbikePayment> getExpireOrderByDuration(int duration) {
QueryColumn time = QueryMethods.secToTime(String.valueOf(duration * 60));
// trade_state 等于 NOTPAY未支付的 并且创建时间超过duration分钟的订单
// trade_state 等于 NOTPAY未支付的 USERPAYING正在支持的 并且创建时间超过duration分钟的订单
QueryWrapper query = QueryWrapper.create()
.where(EBIKE_PAYMENT.TRADE_STATE.eq(Transaction.TradeStateEnum.USERPAYING.ordinal()))
.where(EBIKE_PAYMENT.TRADE_STATE.eq(Transaction.TradeStateEnum.NOTPAY.ordinal()))
.and(QueryMethods.addTime(EBIKE_PAYMENT.CREATE_TIME, time).ge(QueryMethods.now()));
return list(query);
}
@ -62,6 +62,7 @@ public class EbikePaymentServiceImpl extends ServiceImpl<EbikePaymentMapper, Ebi
ebikePayment.setTotal(v);
String paymentTime = transaction.getSuccessTime();
ebikePayment.setPaymentTime(StringUtils.toLocalDatetime(paymentTime));
ebikePayment.setTransactionId(transaction.getTransactionId());
// 同步支付状态
ResFeignOrderPaymentDto paymentParam = new ResFeignOrderPaymentDto();
paymentParam.setOrderId(Long.valueOf(transaction.getOutTradeNo()));
@ -70,14 +71,14 @@ public class EbikePaymentServiceImpl extends ServiceImpl<EbikePaymentMapper, Ebi
ordersFeignClient.payment(paymentParam);
}
QueryWrapper query = QueryWrapper.create()
.where(EBIKE_PAYMENT.PAYMENT_ID.eq(transaction.getTransactionId()));
.where(EBIKE_PAYMENT.ORDER_ID.eq(transaction.getOutTradeNo()));
return update(ebikePayment, query);
}
@Override
public EbikePayment getByPaymentId(String paymentId) {
public EbikePayment getByOrderId(String orderId) {
QueryWrapper query = QueryWrapper.create()
.where(EBIKE_PAYMENT.PAYMENT_ID.eq(paymentId));
.where(EBIKE_PAYMENT.ORDER_ID.eq(orderId));
return this.getOne(query);
}
}

View File

@ -81,8 +81,43 @@ public class WxPayServiceImpl implements WxPayService {
}
}
@Override
public JSONObject prepay(String outTradeNo, String description, String goodsTag, String openId, AmountDto amount, DetailDto detail, String clientIp) {
public JSONObject prepay(String outTradeNo){
// 首先检查订单是否正在付中或者已经支付成功
EbikePayment ebikePayment = ebikePaymentService.getByOrderId(outTradeNo);
if (ebikePayment != null) {
if (String.valueOf(Transaction.TradeStateEnum.SUCCESS.ordinal()).equals(ebikePayment.getTradeState())) {
log.info("订单已经支付成功,订单号:{}", outTradeNo);
return null;
}
if (String.valueOf(Transaction.TradeStateEnum.NOTPAY.ordinal()).equals(ebikePayment.getTradeState())
||String.valueOf(Transaction.TradeStateEnum.USERPAYING.ordinal()).equals(ebikePayment.getTradeState())) {
log.info("订单正在支付中,订单号:{}", outTradeNo);
return null;
}
}
//查询订单, orderFeingClient.getOrderById(orderId)
//获取当前用户openId
return null;
}
/**
* JSAPI支付下单
*
* @param outTradeNo 商户(骑行)订单号
* @param description 商品描述
* @param goodsTag 商品标记
* @param openId 用户标识
* @param amount 金额
* @param detail 商品详情
* @param ebikePayment 原始支付记录
* @return 下单成功返回true否则返回false
*/
private JSONObject prepay(String outTradeNo, String description, String goodsTag, String openId, AmountDto amount, DetailDto detail, EbikePayment ebikePayment) {
try {
PrepayRequest request = new PrepayRequest();
request.setAppid(wxPayConfig.getAppId());
@ -112,23 +147,28 @@ public class WxPayServiceImpl implements WxPayService {
detailReq.setCostPrice(BigDecimal.valueOf(detail.getCostPrice()*100.0).intValue());
detailReq.setInvoiceId(detail.getInvoiceId());
request.setDetail(detailReq);
SceneInfo sceneInfo = new SceneInfo();
sceneInfo.setPayerClientIp(clientIp);
request.setSceneInfo(sceneInfo);
PrepayResponse response = wxJsapiService.prepay(request);
String payId = response.getPrepayId();
//入库
//入库 重新发起支付更新记录订单号<-->记录号一一对应
if (payId != null) {
EbikePayment ebikePayment = new EbikePayment();
ebikePayment.setOrderId(outTradeNo);
ebikePayment.setPaymentId(payId);
ebikePayment.setCreateTime(LocalDateTime.now());
ebikePayment.setPaymentMethod(PayMethod.wechat.name());
ebikePayment.setCostPrice(amount.getTotal());
int state = Transaction.TradeStateEnum.USERPAYING.ordinal();
ebikePayment.setTradeState(String.valueOf(state));
ebikePaymentService.save(ebikePayment);
if (ebikePayment == null) {
ebikePayment = new EbikePayment();
ebikePayment.setOrderId(outTradeNo);
ebikePayment.setPaymentId(payId);
ebikePayment.setCreateTime(LocalDateTime.now());
ebikePayment.setPaymentMethod(PayMethod.wechat.name());
ebikePayment.setCostPrice(amount.getTotal());
ebikePayment.setTradeState(String.valueOf(Transaction.TradeStateEnum.NOTPAY.ordinal()));
ebikePaymentService.save(ebikePayment);
}else{
ebikePayment.setPaymentId(payId);
ebikePayment.setCreateTime(LocalDateTime.now());
ebikePayment.setPaymentMethod(PayMethod.wechat.name());
ebikePayment.setCostPrice(amount.getTotal());
ebikePayment.setTradeState(String.valueOf(Transaction.TradeStateEnum.NOTPAY.ordinal()));
ebikePaymentService.updateById(ebikePayment);
}
// 返回给小程序的参数调起微信支付
WxJsapiPromptDto wxJsapiPromptDto = new WxJsapiPromptDto();
wxJsapiPromptDto.setAppId(wxPayConfig.getAppId());
@ -145,28 +185,22 @@ public class WxPayServiceImpl implements WxPayService {
}
}
@Override
public Transaction queryOrderById(String transactionId) {
QueryOrderByIdRequest request = new QueryOrderByIdRequest();
request.setTransactionId(transactionId);
return wxJsapiService.queryOrderById(request);
}
@Override
public Transaction queryOrderByOutTradeNo(String outTradeNo) {
QueryOrderByOutTradeNoRequest request = new QueryOrderByOutTradeNoRequest();
request.setOutTradeNo(outTradeNo);
request.setMchid(wxPayConfig.getMerchantId());
return wxJsapiService.queryOrderByOutTradeNo(request);
}
@Override
public HandleNotifyResult queryOrderStatusById(String transactionId) {
public HandleNotifyResult queryOrderStatusByOutTradeNo(String outTradeNo) {
// 先查本地数据库如果退款状态不为SUCCESS需要查询微信支付
HandleNotifyResult result = new HandleNotifyResult();
EbikePayment ebikePayment = ebikePaymentService.getByPaymentId(transactionId);
EbikePayment ebikePayment = ebikePaymentService.getByOrderId(outTradeNo);
if (ebikePayment==null){
log.error("{}支付订单不存在", transactionId);
result.setMessage(String.format("{%s}支付订单不存在", transactionId));
log.error("{}支付订单不存在", outTradeNo);
result.setMessage(String.format("{%s}支付订单不存在", outTradeNo));
return result;
}
result.setSuccess(String.valueOf(Transaction.TradeStateEnum.SUCCESS.ordinal()).equals(ebikePayment.getTradeState()));
@ -174,9 +208,10 @@ public class WxPayServiceImpl implements WxPayService {
result.setMessage(String.format("订单%s支付成功", ebikePayment.getOrderId()));
return result;
}
QueryOrderByIdRequest request = new QueryOrderByIdRequest();
request.setTransactionId(transactionId);
Transaction r = wxJsapiService.queryOrderById(request);
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)) {
result.setMessage(String.format("订单%s支付成功", ebikePayment.getOrderId()));
result.setSuccess(true);
@ -223,11 +258,14 @@ public class WxPayServiceImpl implements WxPayService {
}
@Override
public String refund(String transactionId, String outTradeNo, String reason, AmountRefundDto amount) {
public String refund(String outTradeNo, String reason) {
// 雪花算法生成退款单号
String outRefundNo = StringUtils.generateSnowflakeId("refundId");
EbikeRefund ebikeRefund = new EbikeRefund();
ebikeRefund.setCreateTime(LocalDateTime.now());
// 查询支付订单
String transactionId = "";
AmountRefundDto amount = new AmountRefundDto();
// 发起退款
CreateRequest request = new CreateRequest();
request.setTransactionId(transactionId);
@ -245,7 +283,7 @@ public class WxPayServiceImpl implements WxPayService {
if (result != null) {
ebikeRefund.setRefundId(outRefundNo);
ebikeRefund.setOrderId(outTradeNo);
ebikeRefund.setPaymentId(transactionId);
ebikeRefund.setTransactionId(transactionId);
ebikeRefund.setTotal(amount.getTotal());
ebikeRefund.setReason(reason);
ebikeRefund.setStatus(String.valueOf(result.getStatus().ordinal()));