feat(transaction): 实现易生支付实时退款功能并优化微信支付流程
- 新增易生支付实时退款功能,实现订单退款操作- 优化微信支付流程,使用微信登录授权码替代原有的openid- 调整订单标题和描述的处理逻辑,提高支付请求的灵活性 - 移除不必要的接口,简化系统架构
This commit is contained in:
parent
4e543a22d2
commit
4ded3b177b
@ -3,16 +3,22 @@ package com.wzj.soopin.transaction.controller;
|
||||
import cn.dev33.satoken.annotation.SaIgnore;
|
||||
import com.wzj.soopin.transaction.domain.bo.PaymentBO;
|
||||
import com.wzj.soopin.transaction.domain.bo.easypay.EasyPayRequest;
|
||||
import com.wzj.soopin.transaction.domain.entity.WxAuthResponse;
|
||||
import com.wzj.soopin.transaction.domain.vo.EasypayPaymentResultVO;
|
||||
import com.wzj.soopin.transaction.domain.vo.EasypayPrePayVO;
|
||||
import com.wzj.soopin.transaction.service.IEasypayService;
|
||||
import com.wzj.soopin.transaction.service.impl.WxAuthService;
|
||||
import io.swagger.v3.oas.annotations.Parameter;
|
||||
import io.swagger.v3.oas.annotations.Parameters;
|
||||
import io.swagger.v3.oas.annotations.enums.ParameterIn;
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.dromara.common.core.domain.R;
|
||||
import org.dromara.common.log.annotation.Log;
|
||||
import org.dromara.common.log.enums.BusinessType;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
import java.rmi.ServerException;
|
||||
@ -37,7 +43,7 @@ public class TransEasypayController {
|
||||
* @return
|
||||
*/
|
||||
@SaIgnore
|
||||
@Log(title = "易生支付结果通知回调", businessType = BusinessType.UPDATE)
|
||||
@Log(title = "易生支付-支付结果通知回调", businessType = BusinessType.UPDATE)
|
||||
@PostMapping("/trade/callback")
|
||||
public Map tradeCallback(@RequestBody EasyPayRequest easyPayRequest) {
|
||||
easypayService.handleTradeCallback(easyPayRequest);
|
||||
@ -53,7 +59,7 @@ public class TransEasypayController {
|
||||
* @param paymentBO
|
||||
* @return
|
||||
*/
|
||||
@Log(title = "发起支付", businessType = BusinessType.OTHER)
|
||||
@Log(title = "易生支付-发起支付", businessType = BusinessType.OTHER)
|
||||
@PostMapping("/trade")
|
||||
public R<EasypayPrePayVO> trade(@RequestBody PaymentBO paymentBO) throws ServerException {
|
||||
EasypayPrePayVO easypayPrePayVO = easypayService.payment(paymentBO);
|
||||
@ -67,8 +73,21 @@ public class TransEasypayController {
|
||||
* @return
|
||||
*/
|
||||
@GetMapping("/paymentQuery/{orderId}")
|
||||
public R<EasypayPaymentResultVO> paymentQuery(@PathVariable("orderId") String orderId) throws ServerException {
|
||||
public R<EasypayPaymentResultVO> paymentQuery(@PathVariable("orderId") Long orderId) throws ServerException {
|
||||
EasypayPaymentResultVO easypayPaymentResultVO = easypayService.paymentQuery(orderId);
|
||||
return R.ok(easypayPaymentResultVO);
|
||||
}
|
||||
|
||||
/**
|
||||
* 实时退款
|
||||
*
|
||||
* @param orderId 订单id
|
||||
* @return
|
||||
*/
|
||||
@Log(title = "易生支付-实时退款", businessType = BusinessType.OTHER)
|
||||
@PostMapping("/refund/{orderId}")
|
||||
public R<EasypayPrePayVO> refund(@PathVariable("orderId") Long orderId) throws ServerException {
|
||||
easypayService.refund(orderId);
|
||||
return R.ok();
|
||||
}
|
||||
}
|
||||
|
@ -179,21 +179,7 @@ public class WxPayController {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 通过小程序的授权码获取用户的openid
|
||||
*
|
||||
* @param code 授权码
|
||||
* @return 包含openid的响应对象
|
||||
*/
|
||||
@Tag(name = "获取用户openid")
|
||||
@GetMapping("/openid2")
|
||||
@Parameters({
|
||||
@Parameter(name = "code", description = "授权码", required = true, in = ParameterIn.QUERY)
|
||||
})
|
||||
public R<WxAuthResponse> getOpenIdByMiniProgramCode(@RequestParam String code) {
|
||||
WxAuthResponse response = wxAuthService.getOpenIdByMiniProgramCode(code);
|
||||
return R.ok(response);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
@ -23,17 +23,6 @@ public class PaymentBO {
|
||||
@NotNull(message = "订单Id不能为空")
|
||||
private Long orderId;
|
||||
|
||||
/**
|
||||
* 订单标题,对应支付宝订单里的 “商品说明”,微信订单里的“商品”
|
||||
*/
|
||||
@NotBlank(message = "订单标题不能为空")
|
||||
private String orderSub;
|
||||
/**
|
||||
* 订单描述
|
||||
*/
|
||||
@NotBlank(message = "订单描述不能为空")
|
||||
private String orderDes;
|
||||
|
||||
/**
|
||||
* 支付方式
|
||||
*/
|
||||
@ -46,9 +35,9 @@ public class PaymentBO {
|
||||
private String buyerId;
|
||||
|
||||
/**
|
||||
* 微信业务参数:微信用户子标识
|
||||
* 微信登录授权码
|
||||
*/
|
||||
private String subOpenId;
|
||||
private String wxLoginCode;
|
||||
|
||||
// ============银联业务参数 start ==============
|
||||
/**
|
||||
|
@ -24,7 +24,7 @@ public interface IEasypayService {
|
||||
* @param orderId
|
||||
* @return
|
||||
*/
|
||||
EasypayPaymentResultVO paymentQuery(String orderId) throws ServerException;
|
||||
EasypayPaymentResultVO paymentQuery(Long orderId) throws ServerException;
|
||||
|
||||
/**
|
||||
* 处理易生支付结果通知回调
|
||||
@ -32,6 +32,12 @@ public interface IEasypayService {
|
||||
*/
|
||||
void handleTradeCallback(EasyPayRequest easyPayRequest);
|
||||
|
||||
/**
|
||||
* 易生退款
|
||||
* @param orderId
|
||||
*/
|
||||
void refund(Long orderId);
|
||||
|
||||
/**
|
||||
* 获取易生账户
|
||||
* @param memberId
|
||||
|
@ -26,6 +26,9 @@ import com.wzj.soopin.transaction.config.EasypayConfig;
|
||||
import com.wzj.soopin.transaction.config.WechatMiniProgramConfig;
|
||||
import com.wzj.soopin.transaction.domain.bo.PaymentBO;
|
||||
import com.wzj.soopin.transaction.domain.bo.easypay.*;
|
||||
import com.wzj.soopin.transaction.domain.bo.easypay.refund.apply.req.RefundApplyReqBody;
|
||||
import com.wzj.soopin.transaction.domain.bo.easypay.refund.apply.req.RefundReqOrderInfo;
|
||||
import com.wzj.soopin.transaction.domain.bo.easypay.refund.apply.resp.RefundApplyRespBody;
|
||||
import com.wzj.soopin.transaction.domain.bo.easypay.trade.jsapi.req.*;
|
||||
import com.wzj.soopin.transaction.domain.bo.easypay.trade.jsapi.resp.JsApiRespBody;
|
||||
import com.wzj.soopin.transaction.domain.bo.easypay.trade.jsapi.resp.JsapiRespOrderInfo;
|
||||
@ -33,6 +36,7 @@ import com.wzj.soopin.transaction.domain.bo.easypay.trade.jsapi.resp.WxJsApiResp
|
||||
import com.wzj.soopin.transaction.domain.bo.easypay.trade.query.req.TradeQueryReqBody;
|
||||
import com.wzj.soopin.transaction.domain.bo.easypay.trade.query.resp.TradeQueryRespBody;
|
||||
import com.wzj.soopin.transaction.domain.bo.easypay.trade.query.resp.TradeQueryRespOrderInfo;
|
||||
import com.wzj.soopin.transaction.domain.entity.WxAuthResponse;
|
||||
import com.wzj.soopin.transaction.domain.po.PayOrder;
|
||||
import com.wzj.soopin.transaction.domain.vo.EasypayAccountVO;
|
||||
import com.wzj.soopin.transaction.domain.vo.EasypayPaymentResultVO;
|
||||
@ -76,12 +80,12 @@ import static com.wzj.soopin.transaction.constans.EasypayConstants.*;
|
||||
@Slf4j
|
||||
public class EasypayServiceImpl implements IEasypayService {
|
||||
|
||||
@Autowired
|
||||
private EasypayConfig easypayConfig;
|
||||
|
||||
@Autowired
|
||||
private WechatMiniProgramConfig wechatMiniProgramConfig;
|
||||
|
||||
private WxAuthService wxAuthService;
|
||||
|
||||
private final OrderMapper orderMapper;
|
||||
|
||||
private final DivideMapper divideMapper;
|
||||
@ -252,7 +256,7 @@ public class EasypayServiceImpl implements IEasypayService {
|
||||
private void checkPaymentParamByPayType(PaymentBO paymentBO) throws ServerException {
|
||||
switch (paymentBO.getPayType()) {
|
||||
case ALI_PAY_JSAPI, ALI_PAY_MINI_APP -> Assert.notBlank(paymentBO.getBuyerId(), () -> new ServiceException("支付宝支付缺少必要参数:buyerId"));
|
||||
case WE_CHAT_JSAPI, WE_CHAT_MINI_APP -> Assert.notBlank(paymentBO.getSubOpenId(), () -> new ServiceException("微信支付缺少必要参数:subOpenId"));
|
||||
case WE_CHAT_JSAPI, WE_CHAT_MINI_APP -> Assert.notBlank(paymentBO.getWxLoginCode(), () -> new ServiceException("微信支付缺少必要参数:微信登录授权code"));
|
||||
case UNION_PAY_JSAPI, UNION_PAY_Js_MINI -> Assert.isTrue(StrUtil.isAllNotBlank(paymentBO.getTransType(), paymentBO.getUserAuthCode(),
|
||||
paymentBO.getUserId(), paymentBO.getAreaInfo(), paymentBO.getPaymentValidTime(),
|
||||
paymentBO.getQrCode(), paymentBO.getQrCodeType()), () -> new ServiceException("银联支付缺少必要参数"));
|
||||
@ -267,29 +271,21 @@ public class EasypayServiceImpl implements IEasypayService {
|
||||
* @param paymentBO
|
||||
*/
|
||||
private void setPayInfo(JsApiReqBody apiReqBody, PaymentBO paymentBO) throws ServerException {
|
||||
switch (paymentBO.getPayType()) {
|
||||
case ALI_PAY_JSAPI, ALI_PAY_MINI_APP -> apiReqBody.setAliBizParam(AliBizParam.builder().buyerId(paymentBO.getBuyerId()).build());
|
||||
case WE_CHAT_JSAPI, WE_CHAT_MINI_APP -> {
|
||||
WxAuthResponse wxAuthResponse = wxAuthService.getOpenIdByMiniProgramCode(paymentBO.getWxLoginCode());
|
||||
Assert.isTrue(StrUtil.equals(wxAuthResponse.getErrcode(), "0"), () -> new ServiceException("微信小程序登录异常"));
|
||||
apiReqBody.setWxBizParam(WxBizParam.builder().subAppid(wechatMiniProgramConfig.getAppId()).subOpenId(wxAuthResponse.getOpenid()).build());
|
||||
}
|
||||
case UNION_PAY_JSAPI, UNION_PAY_Js_MINI -> apiReqBody.setQrBizParam(BeanUtil.copyProperties(paymentBO, QrBizParam.class));
|
||||
default -> throw new ServerException("不支持的支付方式");
|
||||
}
|
||||
PayInfo payInfo = PayInfo.builder()
|
||||
.payType(paymentBO.getPayType().getValue())
|
||||
.transDate(DateUtils.parseDateToStr(FormatsType.YYYYMMDD, new Date()))
|
||||
.build();
|
||||
apiReqBody.setPayInfo(payInfo);
|
||||
switch (paymentBO.getPayType()) {
|
||||
case ALI_PAY_JSAPI, ALI_PAY_MINI_APP -> {
|
||||
Assert.isTrue(StrUtil.isNotBlank(paymentBO.getBuyerId()), () -> new ServiceException("支付宝支付需传入买家ID"));
|
||||
apiReqBody.setAliBizParam(AliBizParam.builder().buyerId(paymentBO.getBuyerId()).build());
|
||||
}
|
||||
case WE_CHAT_JSAPI, WE_CHAT_MINI_APP -> {
|
||||
Assert.isTrue(StrUtil.isAllNotBlank(paymentBO.getSubOpenId()), () -> new ServiceException("微信支付需传入appId和openId"));
|
||||
apiReqBody.setWxBizParam(WxBizParam.builder().subAppid(wechatMiniProgramConfig.getAppId()).subOpenId(paymentBO.getSubOpenId()).build());
|
||||
}
|
||||
case UNION_PAY_JSAPI, UNION_PAY_Js_MINI -> {
|
||||
Assert.isTrue(StrUtil.isAllNotBlank(paymentBO.getTransType(), paymentBO.getUserAuthCode(),
|
||||
paymentBO.getUserId(), paymentBO.getAreaInfo(), paymentBO.getPaymentValidTime(),
|
||||
paymentBO.getQrCode(), paymentBO.getQrCodeType()), () -> new ServiceException("银联支付传入参数不完整"));
|
||||
QrBizParam qrBizParam = BeanUtil.copyProperties(paymentBO, QrBizParam.class);
|
||||
apiReqBody.setQrBizParam(qrBizParam);
|
||||
}
|
||||
default -> throw new ServerException("不支持的支付方式");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@ -323,8 +319,8 @@ public class EasypayServiceImpl implements IEasypayService {
|
||||
.transAmount(transAmount)
|
||||
.backUrl(easypayConfig.getBackUrl())
|
||||
.timeout(String.valueOf(TRACE_TIMEOUT))
|
||||
.orderSub(paymentBO.getOrderSub())
|
||||
.orderDes(paymentBO.getOrderDes())
|
||||
.orderSub("无终街支付订单")
|
||||
.orderDes("无终街支付订单:" + order.getMerchantNote())
|
||||
.build();
|
||||
apiReqBody.setReqOrderInfo(jsapiReqOrderInfo);
|
||||
return payOrder;
|
||||
@ -366,7 +362,7 @@ public class EasypayServiceImpl implements IEasypayService {
|
||||
* @throws ServerException
|
||||
*/
|
||||
@Override
|
||||
public EasypayPaymentResultVO paymentQuery(String orderId) throws ServerException {
|
||||
public EasypayPaymentResultVO paymentQuery(Long orderId) throws ServerException {
|
||||
Order order = orderMapper.selectById(orderId);
|
||||
Assert.notNull(order, () -> new ServiceException("订单不存在"));
|
||||
PayOrder payOrder = payOrderMapper.selectOne(Wrappers.lambdaQuery(PayOrder.class)
|
||||
@ -477,6 +473,39 @@ public class EasypayServiceImpl implements IEasypayService {
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void refund(Long orderId) {
|
||||
Order order = orderMapper.selectById(orderId);
|
||||
Assert.notNull(order, () -> new ServiceException("订单不存在"));
|
||||
PayOrder payOrder = payOrderMapper.selectOne(Wrappers.lambdaQuery(PayOrder.class).eq(PayOrder::getOrderId, orderId).last("limit 1"));
|
||||
Assert.notNull(payOrder, () -> new ServiceException("订单不存在"));
|
||||
EasyPayRequestHeader reqHeader = generateEasyPayRequestHeader();
|
||||
RefundApplyReqBody refundApplyReqBody = RefundApplyReqBody.builder()
|
||||
.reqInfo(ReqInfo.builder().mchtCode(easypayConfig.getMchtCode()).build())
|
||||
.payInfo(PayInfo.builder().transDate(DateUtils.parseDateToStr(FormatsType.YYYYMMDD, new Date())).build())
|
||||
.reqOrderInfo(RefundReqOrderInfo.builder()
|
||||
.orgTrace(StrBuilder.create(TRACE_PREFIX).append(System.currentTimeMillis()).append(RandomUtil.randomString(4)).toString())
|
||||
.oriOrgTrace(String.valueOf(order.getPayId()))
|
||||
.oriTransDate(DateUtils.parseDateToStr(FormatsType.YYYYMMDD,payOrder.getStartTransDate()))
|
||||
.refundAmount(payOrder.getTransAmount())
|
||||
.build())
|
||||
.build();
|
||||
String reqSign = getSignStr(reqHeader, refundApplyReqBody);
|
||||
EasyPayRequest easyRequest = EasyPayRequest.builder()
|
||||
.reqHeader(reqHeader)
|
||||
.reqBody(refundApplyReqBody)
|
||||
.reqSign(reqSign)
|
||||
.build();
|
||||
log.debug("调用易生实时退款接口请求:{}",JSONObject.toJSONString(easyRequest));
|
||||
String url = StrBuilder.create(easypayConfig.getApiPathPrefix()).append("/trade/refund/apply").toString();
|
||||
String body = HttpRequest.post(url)
|
||||
.timeout(3000)
|
||||
.body(JSON.toJSONString(easyRequest))
|
||||
.execute()
|
||||
.body();
|
||||
log.debug("调用易实时退款接口响应:{}",body);
|
||||
RefundApplyRespBody refundApplyRespBody = JSONObject.parseObject(body, RefundApplyRespBody.class);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
|
Loading…
x
Reference in New Issue
Block a user