init
This commit is contained in:
12
sl-express-pay/src/main/java/com/sl/pay/PayApplication.java
Normal file
12
sl-express-pay/src/main/java/com/sl/pay/PayApplication.java
Normal file
@@ -0,0 +1,12 @@
|
||||
package com.sl.pay;
|
||||
|
||||
import org.springframework.boot.SpringApplication;
|
||||
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||
|
||||
@SpringBootApplication
|
||||
public class PayApplication {
|
||||
|
||||
public static void main(String[] args) {
|
||||
SpringApplication.run(PayApplication.class, args);
|
||||
}
|
||||
}
|
@@ -0,0 +1,71 @@
|
||||
package com.sl.pay.constant;
|
||||
|
||||
import com.sl.pay.enums.PayChannelEnum;
|
||||
|
||||
/**
|
||||
* @ClassName TardingConstant.java
|
||||
* @Description 交易常量类
|
||||
*/
|
||||
public class TradingConstant {
|
||||
|
||||
//【阿里云退款返回状态】
|
||||
//REFUND_SUCCESS:成功
|
||||
public static final String REFUND_SUCCESS = "REFUND_SUCCESS";
|
||||
|
||||
//【阿里云返回付款状态】
|
||||
//TRADE_CLOSED:未付款交易超时关闭,或支付完成后全额退款
|
||||
public static final String ALI_TRADE_CLOSED = "TRADE_CLOSED";
|
||||
//TRADE_SUCCESS:交易支付成功
|
||||
public static final String ALI_TRADE_SUCCESS = "TRADE_SUCCESS";
|
||||
//TRADE_FINISHED:交易结束不可退款
|
||||
public static final String ALI_TRADE_FINISHED = "TRADE_FINISHED";
|
||||
|
||||
|
||||
//【微信退款返回状态】
|
||||
//SUCCESS:退款成功
|
||||
public static final String WECHAT_REFUND_SUCCESS = "SUCCESS";
|
||||
//CLOSED:退款关闭
|
||||
public static final String WECHAT_REFUND_CLOSED = "CLOSED";
|
||||
//PROCESSING:退款处理中
|
||||
public static final String WECHAT_REFUND_PROCESSING = "PROCESSING";
|
||||
//ABNORMAL:退款异常
|
||||
public static final String WECHAT_REFUND_ABNORMAL = "TRADE_CLOSED";
|
||||
|
||||
//【微信返回付款状态】
|
||||
//SUCCESS:支付成功
|
||||
public static final String WECHAT_TRADE_SUCCESS = "SUCCESS";
|
||||
//REFUND:转入退款
|
||||
public static final String WECHAT_TRADE_REFUND = "REFUND";
|
||||
//NOTPAY:未支付
|
||||
public static final String WECHAT_TRADE_NOTPAY = "NOTPAY";
|
||||
//CLOSED:已关闭
|
||||
public static final String WECHAT_TRADE_CLOSED = "CLOSED";
|
||||
//REVOKED:已撤销(仅付款码支付会返回)
|
||||
public static final String WECHAT_TRADE_REVOKED = "REVOKED";
|
||||
//USERPAYING:用户支付中(仅付款码支付会返回)
|
||||
public static final String WECHAT_TRADE_USERPAYING = "USERPAYING";
|
||||
//PAYERROR:支付失败(仅付款码支付会返回)
|
||||
public static final String WECHAT_TRADE_PAYERROR = "PAYERROR";
|
||||
|
||||
//【平台:交易渠道】
|
||||
//阿里支付
|
||||
public static final String TRADING_CHANNEL_ALI_PAY = PayChannelEnum.ALI_PAY.name();
|
||||
//微信支付
|
||||
public static final String TRADING_CHANNEL_WECHAT_PAY = PayChannelEnum.WECHAT_PAY.name();
|
||||
//现金
|
||||
public static final String TRADING_CHANNEL_CASH_PAY = "CASH_PAY";
|
||||
//免单挂账【信用渠道】
|
||||
public static final String TRADING_CHANNEL_CREDIT_PAY = "CREDIT_PAY";
|
||||
|
||||
//【平台:交易动作】
|
||||
//付款
|
||||
public static final String TRADING_TYPE_FK = "FK";
|
||||
//退款
|
||||
public static final String TRADING_TYPE_TK = "TK";
|
||||
//免单
|
||||
public static final String TRADING_TYPE_MD = "MD";
|
||||
//挂账
|
||||
public static final String TRADING_TYPE_GZ = "GZ";
|
||||
|
||||
|
||||
}
|
@@ -0,0 +1,60 @@
|
||||
package com.sl.pay.entity;
|
||||
|
||||
import com.baomidou.mybatisplus.annotation.TableName;
|
||||
import com.sl.pay.enums.RefundStatusEnum;
|
||||
import com.sl.transport.common.entity.BaseEntity;
|
||||
import io.swagger.annotations.ApiModelProperty;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
|
||||
/**
|
||||
* @Description:退款记录表
|
||||
*/
|
||||
@Data
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
@TableName("sl_refund_record")
|
||||
public class RefundRecordEntity extends BaseEntity {
|
||||
|
||||
private static final long serialVersionUID = -3998253241655800061L;
|
||||
|
||||
@ApiModelProperty(value = "交易系统订单号【对于三方来说:商户订单】")
|
||||
private Long tradingOrderNo;
|
||||
|
||||
@ApiModelProperty(value = "业务系统订单号")
|
||||
private Long productOrderNo;
|
||||
|
||||
@ApiModelProperty(value = "本次退款订单号")
|
||||
private Long refundNo;
|
||||
|
||||
@ApiModelProperty(value = "商户号")
|
||||
private Long enterpriseId;
|
||||
|
||||
@ApiModelProperty(value = "退款渠道【支付宝、微信、现金】")
|
||||
private String tradingChannel;
|
||||
|
||||
@ApiModelProperty(value = "退款状态")
|
||||
private RefundStatusEnum refundStatus;
|
||||
|
||||
@ApiModelProperty(value = "返回编码")
|
||||
private String refundCode;
|
||||
|
||||
@ApiModelProperty(value = "返回信息")
|
||||
private String refundMsg;
|
||||
|
||||
@ApiModelProperty(value = "备注【订单门店,桌台信息】")
|
||||
private String memo;
|
||||
|
||||
@ApiModelProperty(value = "本次退款金额")
|
||||
private BigDecimal refundAmount;
|
||||
|
||||
@ApiModelProperty(value = "原订单金额")
|
||||
private BigDecimal total;
|
||||
|
||||
|
||||
}
|
@@ -0,0 +1,96 @@
|
||||
package com.sl.pay.entity;
|
||||
|
||||
import com.baomidou.mybatisplus.annotation.TableName;
|
||||
import com.sl.pay.enums.TradingStateEnum;
|
||||
import com.sl.transport.common.entity.BaseEntity;
|
||||
import io.swagger.annotations.ApiModelProperty;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
|
||||
/**
|
||||
* 交易订单表
|
||||
*/
|
||||
@Data
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
@TableName("sl_trading")
|
||||
public class TradingEntity extends BaseEntity {
|
||||
|
||||
private static final long serialVersionUID = -3427581867070559590L;
|
||||
|
||||
@ApiModelProperty(value = "openId标识")
|
||||
private String openId;
|
||||
|
||||
@ApiModelProperty(value = "业务系统订单号")
|
||||
private Long productOrderNo;
|
||||
|
||||
@ApiModelProperty(value = "交易系统订单号【对于三方来说:商户订单】")
|
||||
private Long tradingOrderNo;
|
||||
|
||||
@ApiModelProperty(value = "支付渠道【支付宝、微信、现金、免单挂账】")
|
||||
private String tradingChannel;
|
||||
|
||||
@ApiModelProperty(value = "交易类型【付款、退款、免单、挂账】")
|
||||
private String tradingType;
|
||||
|
||||
@ApiModelProperty(value = "交易单状态【DFK待付款,FKZ付款中,QXDD取消订单,YJS已结算,MD免单,GZ挂账】")
|
||||
private TradingStateEnum tradingState;
|
||||
|
||||
@ApiModelProperty(value = "收款人姓名")
|
||||
private String payeeName;
|
||||
|
||||
@ApiModelProperty(value = "收款人账户ID")
|
||||
private Long payeeId;
|
||||
|
||||
@ApiModelProperty(value = "付款人姓名")
|
||||
private String payerName;
|
||||
|
||||
@ApiModelProperty(value = "付款人Id")
|
||||
private Long payerId;
|
||||
|
||||
@ApiModelProperty(value = "交易金额")
|
||||
private BigDecimal tradingAmount;
|
||||
|
||||
@ApiModelProperty(value = "退款金额【付款后】")
|
||||
private BigDecimal refund;
|
||||
|
||||
@ApiModelProperty(value = "是否有退款:YES,NO")
|
||||
private String isRefund;
|
||||
|
||||
@ApiModelProperty(value = "第三方交易返回编码【最终确认交易结果】")
|
||||
private String resultCode;
|
||||
|
||||
@ApiModelProperty(value = "第三方交易返回提示消息【最终确认交易信息】")
|
||||
private String resultMsg;
|
||||
|
||||
@ApiModelProperty(value = "第三方交易返回信息json【分析交易最终信息】")
|
||||
private String resultJson;
|
||||
|
||||
@ApiModelProperty(value = "统一下单返回编码")
|
||||
private String placeOrderCode;
|
||||
|
||||
@ApiModelProperty(value = "统一下单返回信息")
|
||||
private String placeOrderMsg;
|
||||
|
||||
@ApiModelProperty(value = "统一下单返回信息json【用于生产二维码、Android ios唤醒支付等】")
|
||||
private String placeOrderJson;
|
||||
|
||||
@ApiModelProperty(value = "商户号")
|
||||
private Long enterpriseId;
|
||||
|
||||
@ApiModelProperty(value = "备注【订单门店,桌台信息】")
|
||||
private String memo;
|
||||
|
||||
@ApiModelProperty(value = "二维码base64数据")
|
||||
private String qrCode;
|
||||
|
||||
@ApiModelProperty(value = "是否有效")
|
||||
protected String enableFlag;
|
||||
|
||||
|
||||
}
|
@@ -0,0 +1,38 @@
|
||||
package com.sl.pay.enums;
|
||||
|
||||
import cn.hutool.core.util.EnumUtil;
|
||||
import com.sl.transport.common.enums.BaseEnum;
|
||||
|
||||
/**
|
||||
* 支付渠道枚举
|
||||
*
|
||||
* @author zzj
|
||||
* @version 1.0
|
||||
*/
|
||||
public enum PayChannelEnum implements BaseEnum {
|
||||
|
||||
ALI_PAY(1, "支付宝"),
|
||||
WECHAT_PAY(2, "微信支付");
|
||||
|
||||
private Integer code;
|
||||
private String value;
|
||||
|
||||
PayChannelEnum(Integer code, String value) {
|
||||
this.code = code;
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Integer getCode() {
|
||||
return this.code;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getValue() {
|
||||
return this.value;
|
||||
}
|
||||
|
||||
public static PayChannelEnum codeOf(Integer code) {
|
||||
return EnumUtil.getBy(PayChannelEnum::getCode, code);
|
||||
}
|
||||
}
|
@@ -0,0 +1,38 @@
|
||||
package com.sl.pay.enums;
|
||||
|
||||
import com.baomidou.mybatisplus.annotation.EnumValue;
|
||||
import com.fasterxml.jackson.annotation.JsonValue;
|
||||
import com.sl.transport.common.enums.BaseEnum;
|
||||
|
||||
/**
|
||||
* 退款状态枚举
|
||||
*
|
||||
* @author zzj
|
||||
* @version 1.0
|
||||
*/
|
||||
public enum RefundStatusEnum implements BaseEnum {
|
||||
|
||||
SENDING(1, "退款中"),
|
||||
SUCCESS(2, "成功"),
|
||||
FAIL(3, "失败");
|
||||
|
||||
@EnumValue
|
||||
@JsonValue
|
||||
private Integer code;
|
||||
private String value;
|
||||
|
||||
RefundStatusEnum(Integer code, String value) {
|
||||
this.code = code;
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Integer getCode() {
|
||||
return this.code;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getValue() {
|
||||
return this.value;
|
||||
}
|
||||
}
|
@@ -0,0 +1,68 @@
|
||||
package com.sl.pay.enums;
|
||||
|
||||
import com.sl.transport.common.enums.BaseExceptionEnum;
|
||||
|
||||
/**
|
||||
* 交易枚举
|
||||
*/
|
||||
public enum TradingEnum implements BaseExceptionEnum {
|
||||
|
||||
SUCCEED(1001, 200, "操作成功"),
|
||||
ERROR(1002, "操作失败"),
|
||||
CHECK_TRADING_FAIL(1003, "交易单校验失败"),
|
||||
TRY_LOCK_TRADING_FAIL(1004, "交易单加锁失败"),
|
||||
PAYING_TRADING_FAIL(1005, "交易单支付失败"),
|
||||
TRADING_STATE_SUCCEED(1006, "交易单已完成"),
|
||||
TRADING_STATE_PAYING(1007, "交易单交易中"),
|
||||
CONFIG_EMPTY(1008, "支付配置为空"),
|
||||
CONFIG_ERROR(1009, "支付配置错误"),
|
||||
NATIVE_PAY_FAIL(1010, "统一下单交易失败"),
|
||||
NATIVE_QRCODE_FAIL(1011, "生成二维码失败"),
|
||||
REFUND_FAIL(1012, "查询统一下单交易退款失败"),
|
||||
SAVE_OR_UPDATE_FAIL(1013, "交易单保存或修改失败"),
|
||||
TRADING_TYPE_FAIL(1014, "未定义的交易类型"),
|
||||
NATIVE_QUERY_FAIL(1015, "查询统一下单交易失败"),
|
||||
NATIVE_REFUND_FAIL(1016, "统一下单退款交易失败"),
|
||||
NATIVE_QUERY_REFUND_FAIL(1017, "统一下单查询退款失败"),
|
||||
CASH_PAY_FAIL(1018, "现金交易失败"),
|
||||
CASH_REFUND_FAIL(1019, "统一下单退款交易失败"),
|
||||
CREDIT_PAY_FAIL(1020, "信用交易失败"),
|
||||
LIST_TRADE_STATE_FAIL(1021, "按交易状态查询交易单失败"),
|
||||
NOT_FOUND(1022, "交易单不存在"),
|
||||
CLOSE_FAIL(1023, "关闭交易单失败"),
|
||||
BASIC_REFUND_OUT_FAIL(1024, "退款金额超过订单总金额"),
|
||||
REFUND_NOT_FOUND(1025, "退款记录不存在"),
|
||||
REFUND_ALREADY_COMPLETED(1026, "退款记录已经完成"),
|
||||
BASIC_REFUND_COUNT_OUT_FAIL(1027, "退款次数超出限制,最多20次"),
|
||||
TRADING_QUERY_PARAM_ERROR(1028, "查询交易单错误,订单号或交易单号至少传递一个"),
|
||||
REFUND_QUERY_PARAM_ERROR(1029, "查询退款单错误,订单号或交易单号至少传递一个");
|
||||
|
||||
private Integer code;
|
||||
private Integer status;
|
||||
private String value;
|
||||
|
||||
TradingEnum(Integer code, String value) {
|
||||
this.code = code;
|
||||
this.value = value;
|
||||
this.status = 500;
|
||||
}
|
||||
|
||||
TradingEnum(Integer code, Integer status, String value) {
|
||||
this.code = code;
|
||||
this.value = value;
|
||||
this.status = status;
|
||||
}
|
||||
|
||||
public Integer getCode() {
|
||||
return code;
|
||||
}
|
||||
|
||||
public String getValue() {
|
||||
return this.value;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Integer getStatus() {
|
||||
return this.status;
|
||||
}
|
||||
}
|
@@ -0,0 +1,42 @@
|
||||
package com.sl.pay.enums;
|
||||
|
||||
import com.baomidou.mybatisplus.annotation.EnumValue;
|
||||
import com.fasterxml.jackson.annotation.JsonValue;
|
||||
import com.sl.transport.common.enums.BaseEnum;
|
||||
|
||||
/**
|
||||
* 交易单状态枚举
|
||||
*
|
||||
* @author zzj
|
||||
* @version 1.0
|
||||
*/
|
||||
public enum TradingStateEnum implements BaseEnum {
|
||||
|
||||
DFK(1, "待付款"),
|
||||
FKZ(2, "付款中"),
|
||||
FKSB(3, "付款失败"),
|
||||
YJS(4, "已结算(已付款)"),
|
||||
QXDD(5, "取消订单"),
|
||||
MD(6, "免单"),
|
||||
GZ(7, "挂账");
|
||||
|
||||
@EnumValue
|
||||
@JsonValue
|
||||
private Integer code;
|
||||
private String value;
|
||||
|
||||
TradingStateEnum(Integer code, String value) {
|
||||
this.code = code;
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Integer getCode() {
|
||||
return this.code;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getValue() {
|
||||
return this.value;
|
||||
}
|
||||
}
|
@@ -0,0 +1,42 @@
|
||||
package com.sl.pay.handler;
|
||||
|
||||
import com.sl.pay.entity.RefundRecordEntity;
|
||||
import com.sl.pay.entity.TradingEntity;
|
||||
import com.sl.transport.common.exception.SLException;
|
||||
|
||||
/**
|
||||
* 基础支付功能的定义,具体业务由不同的支付渠道实现
|
||||
*/
|
||||
public interface BasicPayHandler {
|
||||
|
||||
/***
|
||||
* 统一收单线下交易查询
|
||||
* 该接口提供所有支付订单的查询,商户可以通过该接口主动查询订单状态,完成下一步的业务逻辑。
|
||||
* @return 是否有变化
|
||||
*/
|
||||
Boolean queryTrading(TradingEntity trading) throws SLException;
|
||||
|
||||
/***
|
||||
* 关闭交易
|
||||
* @return 是否成功
|
||||
*/
|
||||
Boolean closeTrading(TradingEntity trading) throws SLException;
|
||||
|
||||
/***
|
||||
* 统一收单交易退款接口
|
||||
* 当交易发生之后一段时间内,由于买家或者卖家的原因需要退款时,卖家可以通过退款接口将支付款退还给买家,
|
||||
* 将在收到退款请求并且验证成功之后,按照退款规则将支付款按原路退到买家帐号上。
|
||||
* @param refundRecord 退款记录对象
|
||||
* @return 是否有变化
|
||||
*/
|
||||
Boolean refundTrading(RefundRecordEntity refundRecord) throws SLException;
|
||||
|
||||
/***
|
||||
* 统一收单交易退款查询接口
|
||||
*
|
||||
* @param refundRecord 退款交易单号
|
||||
* @return 是否有变化
|
||||
*/
|
||||
Boolean queryRefundTrading(RefundRecordEntity refundRecord) throws SLException;
|
||||
|
||||
}
|
@@ -0,0 +1,19 @@
|
||||
package com.sl.pay.handler;
|
||||
|
||||
import com.sl.pay.entity.TradingEntity;
|
||||
import com.sl.transport.common.exception.SLException;
|
||||
|
||||
/**
|
||||
* Native支付方式Handler:商户生成二维码,用户扫描支付
|
||||
*/
|
||||
public interface NativePayHandler {
|
||||
|
||||
|
||||
/***
|
||||
* 统一收单线下交易预创建
|
||||
* 收银员通过收银台或商户后台调用此接口,生成二维码后,展示给用户,由用户扫描二维码完成订单支付。
|
||||
* @param tradingEntity 交易单
|
||||
*/
|
||||
void createDownLineTrading(TradingEntity tradingEntity) throws SLException;
|
||||
|
||||
}
|
@@ -0,0 +1,146 @@
|
||||
package com.sl.pay.handler.alipay;
|
||||
|
||||
import cn.hutool.core.convert.Convert;
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import cn.hutool.json.JSONUtil;
|
||||
import com.alipay.easysdk.factory.Factory;
|
||||
import com.alipay.easysdk.kernel.util.ResponseChecker;
|
||||
import com.alipay.easysdk.payment.common.models.AlipayTradeCloseResponse;
|
||||
import com.alipay.easysdk.payment.common.models.AlipayTradeFastpayRefundQueryResponse;
|
||||
import com.alipay.easysdk.payment.common.models.AlipayTradeQueryResponse;
|
||||
import com.alipay.easysdk.payment.common.models.AlipayTradeRefundResponse;
|
||||
import com.sl.pay.constant.TradingConstant;
|
||||
import com.sl.pay.entity.RefundRecordEntity;
|
||||
import com.sl.pay.entity.TradingEntity;
|
||||
import com.sl.pay.enums.RefundStatusEnum;
|
||||
import com.sl.pay.enums.TradingEnum;
|
||||
import com.sl.pay.enums.TradingStateEnum;
|
||||
import com.sl.pay.handler.BasicPayHandler;
|
||||
import com.sl.transport.common.exception.SLException;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
/**
|
||||
* 支付宝基础支付功能的实现
|
||||
*/
|
||||
@Slf4j
|
||||
@Component("aliBasicPayHandler")
|
||||
public class AliBasicPayHandler implements BasicPayHandler {
|
||||
|
||||
@Override
|
||||
public Boolean queryTrading(TradingEntity trading) throws SLException {
|
||||
//Factory使用配置
|
||||
Factory.setOptions(AlipayConfig.getConfig());
|
||||
AlipayTradeQueryResponse queryResponse;
|
||||
try {
|
||||
//调用支付宝API:通用查询支付情况
|
||||
queryResponse = Factory
|
||||
.Payment
|
||||
.Common()
|
||||
.query(String.valueOf(trading.getTradingOrderNo()));
|
||||
} catch (Exception e) {
|
||||
String msg = StrUtil.format("查询支付宝统一下单失败:trading = {}", trading);
|
||||
log.error(msg, e);
|
||||
throw new SLException(msg);
|
||||
}
|
||||
|
||||
//修改交易单状态
|
||||
trading.setResultCode(queryResponse.getCode());
|
||||
trading.setResultMsg(queryResponse.getSubMsg());
|
||||
trading.setResultJson(JSONUtil.toJsonStr(queryResponse));
|
||||
|
||||
boolean success = ResponseChecker.success(queryResponse);
|
||||
//响应成功,分析交易状态
|
||||
if (success) {
|
||||
String tradeStatus = queryResponse.getTradeStatus();
|
||||
if (StrUtil.equals(TradingConstant.ALI_TRADE_CLOSED, tradeStatus)) {
|
||||
//支付取消:TRADE_CLOSED(未付款交易超时关闭,或支付完成后全额退款)
|
||||
trading.setTradingState(TradingStateEnum.QXDD);
|
||||
} else if (StrUtil.equalsAny(tradeStatus, TradingConstant.ALI_TRADE_SUCCESS, TradingConstant.ALI_TRADE_FINISHED)) {
|
||||
// TRADE_SUCCESS(交易支付成功)
|
||||
// TRADE_FINISHED(交易结束,不可退款)
|
||||
trading.setTradingState(TradingStateEnum.YJS);
|
||||
} else {
|
||||
//非最终状态不处理,当前交易状态:WAIT_BUYER_PAY(交易创建,等待买家付款)不处理
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
throw new SLException(trading.getResultJson(), TradingEnum.NATIVE_QUERY_FAIL.getCode(), TradingEnum.NATIVE_QUERY_FAIL.getStatus());
|
||||
}
|
||||
|
||||
@Override
|
||||
public Boolean closeTrading(TradingEntity trading) throws SLException {
|
||||
//Factory使用配置
|
||||
Factory.setOptions(AlipayConfig.getConfig());
|
||||
try {
|
||||
//调用支付宝API:通用查询支付情况
|
||||
AlipayTradeCloseResponse closeResponse = Factory
|
||||
.Payment
|
||||
.Common()
|
||||
.close(String.valueOf(trading.getTradingOrderNo()));
|
||||
boolean success = ResponseChecker.success(closeResponse);
|
||||
if (success) {
|
||||
trading.setTradingState(TradingStateEnum.QXDD);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
} catch (Exception e) {
|
||||
throw new SLException(TradingEnum.CLOSE_FAIL, e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Boolean refundTrading(RefundRecordEntity refundRecord) throws SLException {
|
||||
//Factory使用配置
|
||||
Factory.setOptions(AlipayConfig.getConfig());
|
||||
//调用支付宝API:通用查询支付情况
|
||||
AlipayTradeRefundResponse refundResponse;
|
||||
try {
|
||||
// 支付宝easy sdk
|
||||
refundResponse = Factory
|
||||
.Payment
|
||||
.Common()
|
||||
//扩展参数:退款单号
|
||||
.optional("out_request_no", refundRecord.getRefundNo())
|
||||
.refund(Convert.toStr(refundRecord.getTradingOrderNo()),
|
||||
Convert.toStr(refundRecord.getRefundAmount()));
|
||||
} catch (Exception e) {
|
||||
String msg = StrUtil.format("调用支付宝退款接口出错!refundRecord = {}", refundRecord);
|
||||
log.error(msg, e);
|
||||
throw new SLException(msg, TradingEnum.NATIVE_REFUND_FAIL.getCode(), TradingEnum.NATIVE_REFUND_FAIL.getStatus());
|
||||
}
|
||||
refundRecord.setRefundCode(refundResponse.getCode());
|
||||
refundRecord.setRefundMsg(JSONUtil.toJsonStr(refundResponse));
|
||||
boolean success = ResponseChecker.success(refundResponse);
|
||||
if (success) {
|
||||
refundRecord.setRefundStatus(RefundStatusEnum.SUCCESS);
|
||||
return true;
|
||||
}
|
||||
throw new SLException(refundRecord.getRefundMsg(), TradingEnum.NATIVE_REFUND_FAIL.getCode(), TradingEnum.NATIVE_REFUND_FAIL.getStatus());
|
||||
}
|
||||
|
||||
@Override
|
||||
public Boolean queryRefundTrading(RefundRecordEntity refundRecord) throws SLException {
|
||||
//Factory使用配置
|
||||
Factory.setOptions(AlipayConfig.getConfig());
|
||||
AlipayTradeFastpayRefundQueryResponse response;
|
||||
try {
|
||||
response = Factory.Payment.Common().queryRefund(
|
||||
Convert.toStr(refundRecord.getTradingOrderNo()),
|
||||
Convert.toStr(refundRecord.getRefundNo()));
|
||||
} catch (Exception e) {
|
||||
log.error("调用支付宝查询退款接口出错!refundRecord = {}", refundRecord, e);
|
||||
throw new SLException(TradingEnum.NATIVE_REFUND_FAIL, e);
|
||||
}
|
||||
|
||||
refundRecord.setRefundCode(response.getCode());
|
||||
refundRecord.setRefundMsg(JSONUtil.toJsonStr(response));
|
||||
boolean success = ResponseChecker.success(response);
|
||||
if (success) {
|
||||
refundRecord.setRefundStatus(RefundStatusEnum.SUCCESS);
|
||||
return true;
|
||||
}
|
||||
throw new SLException(refundRecord.getRefundMsg(), TradingEnum.NATIVE_REFUND_FAIL.getCode(), TradingEnum.NATIVE_REFUND_FAIL.getStatus());
|
||||
}
|
||||
}
|
@@ -0,0 +1,20 @@
|
||||
package com.sl.pay.handler.alipay;
|
||||
|
||||
import com.sl.pay.entity.TradingEntity;
|
||||
import com.sl.pay.handler.NativePayHandler;
|
||||
import com.sl.transport.common.exception.SLException;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
/**
|
||||
* 支付宝实现类
|
||||
*/
|
||||
@Component("aliNativePayHandler")
|
||||
public class AliNativePayHandler implements NativePayHandler {
|
||||
|
||||
@Override
|
||||
public void createDownLineTrading(TradingEntity tradingEntity) throws SLException {
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
@@ -0,0 +1,62 @@
|
||||
package com.sl.pay.handler.alipay;
|
||||
|
||||
import com.alipay.easysdk.kernel.Config;
|
||||
|
||||
/**
|
||||
* 支付宝支付的配置
|
||||
*/
|
||||
public class AlipayConfig {
|
||||
|
||||
/**
|
||||
* 获取支付宝的配置(沙箱环境)
|
||||
*
|
||||
* @return 支付宝的配置
|
||||
*/
|
||||
public static Config getConfig() {
|
||||
Config config = new Config();
|
||||
config.protocol = "https";
|
||||
config.gatewayHost = "openapi.alipaydev.com";
|
||||
config.signType = "RSA2";
|
||||
config.appId = "2016072800110403";
|
||||
// 为避免私钥随源码泄露,推荐从文件中读取私钥字符串而不是写入源码中
|
||||
config.merchantPrivateKey = "MIIEuwIBADANBgkqhkiG9w0BAQEFAASCBKUwggShAgEAAoIBAQDC+zz3NxpflpUlgNIkHWUjlal5JzaqtswH4b4c5c/tshm7zYNHYDu5n9vXW6X8DjnY4JKi9o4iQkps/M7CSOObhdxhzg4m2cppXS8iphnKAdeOb5AV740KOv84addPlNesghKZIV2Q2hpQL067D1Pt4BjbYPAt02dWDIo6yEiGyclCp0xgXm0zBDNZC69MPz634Xz4SZFnfqWrlct4UhKbZj9DvKjq7LIwEapJWe9WscUXChjtuqIjiXPJffq5+AwdKlVFs2yuPlZ7dnYnjHZ1rOpyIxmLL9mo3F2hwVgEisccZ6sdkP+XZnuAZwB28FENLQ9BO/iDk2QyK6rC8HuxAgMBAAECgf8m1+ZNWaznXhhYYFF84F5FuIsKl8VMPR5oc5BsMVw6/kAiKc79aS58zFv/i0KF9E+R5StRS80FBi/Nho+qJNszIHfHBEXNd5XbZ7T8MhrxI2zN82vA8vgmEZrGok9Ci2Rr+X27A+qf8NNNJh+JJIST3xEUozs15eewPM9M5pmMQE1kr7cnX3L9Mq9vF5kDTGR1qPo7aOvMNOPYueAvUqIEQ3mwMW8vN0PZ4OgSyPTQcVMLH50GJ1mCNl2AFK2To4HneOwVtzhnq6FL5gWaOfpsssBVual9Kwv1OxljBY9VRv65+4Eu595MuZ/U8nVD2Sv2nJyb5a4GX2Xg3qEAMC0CgYEA9o4GQ9IG6BRN8oA/a3Rvf/wVgE5Y6/i83WOqG/JNI/kLvgO/nOkIUpNILOOLVLW02328GW2QT9bPB1iyOVXGTUojfN9eCK8lvTT/OhRvOrn/jZxQOUqX1ckyOaNwf0zraKReryehjs3mC0anc1qmAFV2G+pWKeXeQ9P9S0Q9m4cCgYEAynNuSpz1HulEb97vPkvIsOOwselAMPCgNnIBKHDxxMYCs7AVh5o8eF/UvuTYfoXjHl/XQAPYIcxqvjJSY7z1FnPBcTX0fH0idk3aB10pYJ8u/Uvm+EZ3NW/XB8uDT2ggO0/9yO7bGmwrfH0nggGnftbrR5CUCz4SYFzWfkNhrQcCgYEA9W8GD4dItshXm7pM55Pd1sLDSJk1bZmLsLsgwHcgkVm+daXXncRgM4tHwt+0eFv1sLVmhM2LZd7I8mA58ldPcusFjq3wNqbb45CZLWDgJM649WgQeCeoI/oH1Fa9iwuwH9fYJXZHHhgbE0h/MpafPx/T1hAdO9IGwvCJad6BkYsCgYAthJyEnBukso/Xk0k5OXLLCrZ8mdP77O4or6NBA3voYRjUa7+7eFsmOW2s6ekfMV0qRCQyWWrr1nkdgFTz5dU5EhepK5dnsf7gmIpv42tdNQ0smDc7FSTSV+4B66j/Xor4qviFh+atXyq716vdWB/frdTCh2gxyuf40IbNZrr8WwKBgELF5s5ktXcOqRDw8J3JW5CXiwKVsLX6if+mK77NdoGChX1ffX+0BKKLOqMZfhpB0HpqlA/20AwKhX0/BiiV2devl+jabzwST8vg9aT7NHjOePOMdE2bJ+fcJGhLqOdg5Qo+yM/a3irBUYFvJpK66TG46LFbLNxugKOqxZvXyucM";
|
||||
//注:证书文件路径支持设置为文件系统中的路径或CLASS_PATH中的路径,优先从文件系统中加载,加载失败后会继续尝试从CLASS_PATH中加载
|
||||
// config.merchantCertPath = "<-- 请填写您的应用公钥证书文件路径,例如:/foo/appCertPublicKey_2019051064521003.crt -->";
|
||||
// config.alipayCertPath = "<-- 请填写您的支付宝公钥证书文件路径,例如:/foo/alipayCertPublicKey_RSA2.crt -->";
|
||||
// config.alipayRootCertPath = "<-- 请填写您的支付宝根证书文件路径,例如:/foo/alipayRootCert.crt -->";
|
||||
//注:如果采用非证书模式,则无需赋值上面的三个证书路径,改为赋值如下的支付宝公钥字符串即可
|
||||
config.alipayPublicKey = "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAgg7i0fycEzG6z2PUE/t8Mc3M+/c48R4f2soZeI+A0G1gX0/ejLFnVPBofkWJ1mVzXjR4bTlX/DhXnDad1xt4TqPEp65uPuWRt1gSwcaTM41DenoXCcfPwd3J6Vf2AVJ4YEv7716ovK+/e+UzxL9M2mm8jIb1Pr1p2DDc66MlAkqHwIVGYDK+tHJJy4fjFhqRz3NSRSeY2uZi8aOtF5otSIrYxZFrYjMjrdGGVj67mKUQi/ZDaoaTzTH64tEQ21IXbmjJH0EmVdxseJ/N39heHmeXSzcpJCDirXZGqDO2PpZOLH4zibkZEjd/Q6wRFGVWaWFhQ7KtbnDuqQt/74M8SQIDAQAB";
|
||||
//可设置异步通知接收服务地址(可选)
|
||||
config.notifyUrl = "https://www.test.com/callback";
|
||||
//可设置AES密钥,调用AES加解密相关接口时需要(可选)
|
||||
config.encryptKey = "D/9fBsybuxt5ARPYcWDL5g==";
|
||||
return config;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取支付宝的配置(正式环境)
|
||||
*
|
||||
* @return 支付宝的配置
|
||||
*/
|
||||
// public static Config getConfig() {
|
||||
// Config config = new Config();
|
||||
// config.protocol = "https";
|
||||
// config.gatewayHost = "openapi.alipay.com";
|
||||
// config.signType = "RSA2";
|
||||
// config.appId = "2021003141676135";
|
||||
// // 为避免私钥随源码泄露,推荐从文件中读取私钥字符串而不是写入源码中
|
||||
// config.merchantPrivateKey = "MIIEuwIBADANBgkqhkiG9w0BAQEFAASCBKUwggShAgEAAoIBAQC12YM9mR+HFQYTx/fHKHZbgszVtDHDB0B/ysWl3MbcPpGtjcZlDr5aynRMRLaoduRHT++A98IaNVIVGj9RHdXrX2j9I/Uz6fYDH63cdu6FZ6Pk82yPwNZW7pebprbVHInR/7gzsKQWSWEST70BgjCRqlbfAE6xzUZFTeYxciCjptm0rUQ2MC24xRdkvZByIDIYFnQ/AdmSFqNtKDR2WpEV/M8aBjyuPPomRJZ1X8oudWuJIU4ySdas04fCbDxD10TY/wyQcDHXuG1IrQpXme4DOGQeJZ0/aOFphBkDFUyPGfYMmLshOPNdBKi2IqWHPPs4XsV4Rv6+tvTSnMF2uGqHAgMBAAECggEAPa1sifPpcZN74DGupGng2uDeQI1BY3iOM8m+h6b9+61tE4RGifgaMAkCsOuNWE4a1uURwphFyUXUdTvVxdlsuMw/e7w6akUsH5sbCO99rtmcCQdXBtrM1+dMnIpK8LUhOYyWGVIMFVMGDYPmAyD5AC7aEAC2sC+DafYl4RdoYpidq1YxeE7DVw1aQHCI2mKhYjZG+3RDDGDfNFvdyH61MgdYjoGkeXNvARzEXgfWvfiTrHZ3H1SYgvOEHofzKDTrWsQL2dvaEsc55Jiw0AgNUVcgby7al8PUekTJoK3ZvrE3pSWaUirBcqsqWISHjeR7Xx501CHIha8EnZwlnDoM4QKBgQDtnYzwQ5mHg7cRHD8Z6QdTpvBvYSEPesiUT/HeI+AKQKDCVJxKiLvJagc6zZkOzV9bZDS/WLgzXWMyxUb+OTjht0jLWAMcf7NfFp3tPKq9wkmQQ/vQSBQ1lFmO6A4Zq1eoGKeUCB4pKBG6cSM+t8+ruhm7s1ZUt+6EBwCVN/izrQKBgQDD62jIm+6NFErdidUaIrGiFUrzqdR13w6JOexfk+O6Aau3wRqsr7Wz4nqQvVVxGMRpXbOH06zpeiS+vMmjwgO973VoLAmH+hJ0GZz8qj3zA2GEOFWjD2V7tqeRvGkQvz0v46pl+8sBJkrRHLN7DWNYY5NDI+b7exwqcTc/LL19gwJ/a6r4MeZvqvgD+7zQ2uy8ZSs/xzg7wsfgG1QeRIn8+qhOL8AnEZ7jeGCS5hJDSHHGw6KkRA/vZ1bpnBfIE2naXGywj3NR9Zfnry6QYO8cbt+adcRYVghTH/QYoKiFuxvonEKPrIQBJqUBY3ngforLjwTEpEie1cSCT1Dc8sBp8QKBgQCaz8fqzRyBKknGKQXVMxj+JKknRUl3IpzP3o9jLu9BqdRQzSwQzH9d91Y2TQXY6mM5hys35xG5JCUo+vCyj7p5OWCiwjl90yMFzr93/+YXwtIpsoIo6R+d1EUxKZoz+4mT7+hT0dUlwWZZOr6wO3IHBBf3c8UvbqZg+zlWmDnblQKBgEs6jwMkb5zaG2fyBJ7PJUN/8nIz8V+X0SxQfcEqIX0J+EC+7MAgFjcdZFp+lca3Vd9z+8Ksd4rMzMa5y856ositL2NZ+K0fs8i8EBaQPny61OgCFUuXEuv5keB2YuGMSns5FYRWuByrtDXl4PxzKXvq05iKWLKCaCq9v4momvKZ";
|
||||
// //注:证书文件路径支持设置为文件系统中的路径或CLASS_PATH中的路径,优先从文件系统中加载,加载失败后会继续尝试从CLASS_PATH中加载
|
||||
// // config.merchantCertPath = "<-- 请填写您的应用公钥证书文件路径,例如:/foo/appCertPublicKey_2019051064521003.crt -->";
|
||||
// // config.alipayCertPath = "<-- 请填写您的支付宝公钥证书文件路径,例如:/foo/alipayCertPublicKey_RSA2.crt -->";
|
||||
// // config.alipayRootCertPath = "<-- 请填写您的支付宝根证书文件路径,例如:/foo/alipayRootCert.crt -->";
|
||||
// //注:如果采用非证书模式,则无需赋值上面的三个证书路径,改为赋值如下的支付宝公钥字符串即可
|
||||
// config.alipayPublicKey = "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAhUnjdAKwZApwZEcfq+5L0pa77Vg3mqcoXv+th8RR0SYotkPsH1f2JkbS48ySaSCM6YNWSMNfqp5qdOla2zUJOBnJ/yaBg7s7fVD6V3M2mEog8kCDYGKt/3P4VII3xYl8lFYMQ3IcFRELkxCBBCA8JDKmf5z2R4F/Z/jFFEuOwxaJvp+7Ke9OzZHYdWGNnU6QP8YYLYUeX7VNZLHEuly34ExAw6A+yJkNDsYEho2Lu31QjT2pLh9g+88MlRfiI92iN25O9NVdeM4f5RcpvBPrBQZQs9tlFmALYSFS3prIf3FAobWM+W7iwxT6J25nFIhst1DdJQfIBpaeRUJVTkn99QIDAQAB";
|
||||
// //可设置异步通知接收服务地址(可选)
|
||||
// config.notifyUrl = "https://www.test.com/callback";
|
||||
// //可设置AES密钥,调用AES加解密相关接口时需要(可选)
|
||||
// config.encryptKey = "VCS4bdmoAgXRaOq/TQ4MwA==";
|
||||
// return config;
|
||||
// }
|
||||
|
||||
}
|
@@ -0,0 +1,190 @@
|
||||
package com.sl.pay.handler.wechat;
|
||||
|
||||
import cn.hutool.core.convert.Convert;
|
||||
import cn.hutool.core.date.LocalDateTimeUtil;
|
||||
import cn.hutool.core.map.MapUtil;
|
||||
import cn.hutool.core.util.NumberUtil;
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import cn.hutool.json.JSONObject;
|
||||
import cn.hutool.json.JSONUtil;
|
||||
import com.sl.pay.constant.TradingConstant;
|
||||
import com.sl.pay.entity.RefundRecordEntity;
|
||||
import com.sl.pay.entity.TradingEntity;
|
||||
import com.sl.pay.enums.RefundStatusEnum;
|
||||
import com.sl.pay.enums.TradingStateEnum;
|
||||
import com.sl.pay.handler.BasicPayHandler;
|
||||
import com.sl.pay.handler.wechat.response.WeChatResponse;
|
||||
import com.sl.transport.common.exception.SLException;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import java.time.temporal.ChronoUnit;
|
||||
import java.util.Map;
|
||||
|
||||
import static com.sl.pay.enums.TradingEnum.*;
|
||||
|
||||
/**
|
||||
* 微信基础支付功能的实现
|
||||
*/
|
||||
@Slf4j
|
||||
@Component("weChatBasicPayHandler")
|
||||
public class WeChatBasicPayHandler implements BasicPayHandler {
|
||||
|
||||
@Override
|
||||
public Boolean queryTrading(TradingEntity trading) throws SLException {
|
||||
// 获取微信支付的client对象
|
||||
WechatPayHttpClient client = WechatPayHttpClient.get();
|
||||
|
||||
//请求地址
|
||||
String apiPath = StrUtil.format("/v3/pay/transactions/out-trade-no/{}", trading.getTradingOrderNo());
|
||||
|
||||
//请求参数
|
||||
Map<String, Object> params = MapUtil.<String, Object>builder()
|
||||
.put("mchid", client.getMchId())
|
||||
.build();
|
||||
|
||||
WeChatResponse response;
|
||||
try {
|
||||
response = client.doGet(apiPath, params);
|
||||
} catch (Exception e) {
|
||||
log.error("调用微信接口出错!apiPath = {}, params = {}", apiPath, JSONUtil.toJsonStr(params), e);
|
||||
throw new SLException(NATIVE_REFUND_FAIL, e);
|
||||
}
|
||||
if (response.isOk()) {
|
||||
JSONObject jsonObject = JSONUtil.parseObj(response.getBody());
|
||||
// 交易状态,枚举值:
|
||||
// SUCCESS:支付成功
|
||||
// REFUND:转入退款
|
||||
// NOTPAY:未支付
|
||||
// CLOSED:已关闭
|
||||
// REVOKED:已撤销(仅付款码支付会返回)
|
||||
// USERPAYING:用户支付中(仅付款码支付会返回)
|
||||
// PAYERROR:支付失败(仅付款码支付会返回)
|
||||
String tradeStatus = jsonObject.getStr("trade_state");
|
||||
if (StrUtil.equalsAny(tradeStatus, TradingConstant.WECHAT_TRADE_CLOSED, TradingConstant.WECHAT_TRADE_REVOKED)) {
|
||||
trading.setTradingState(TradingStateEnum.QXDD);
|
||||
} else if (StrUtil.equalsAny(tradeStatus, TradingConstant.WECHAT_REFUND_SUCCESS, TradingConstant.WECHAT_TRADE_REFUND)) {
|
||||
trading.setTradingState(TradingStateEnum.YJS);
|
||||
} else if (StrUtil.equalsAny(tradeStatus, TradingConstant.WECHAT_TRADE_NOTPAY)) {
|
||||
//如果是未支付,需要判断下时间,超过2小时未知的订单需要关闭订单以及设置状态为QXDD
|
||||
long between = LocalDateTimeUtil.between(trading.getCreated(), LocalDateTimeUtil.now(), ChronoUnit.HOURS);
|
||||
if (between >= 2) {
|
||||
return this.closeTrading(trading);
|
||||
}
|
||||
} else {
|
||||
//非最终状态不处理
|
||||
return false;
|
||||
}
|
||||
//修改交易单状态
|
||||
trading.setResultCode(tradeStatus);
|
||||
trading.setResultMsg(jsonObject.getStr("trade_state_desc"));
|
||||
trading.setResultJson(response.getBody());
|
||||
return true;
|
||||
}
|
||||
throw new SLException(response.getBody(), NATIVE_REFUND_FAIL.getCode(), NATIVE_REFUND_FAIL.getCode());
|
||||
}
|
||||
|
||||
@Override
|
||||
public Boolean closeTrading(TradingEntity trading) throws SLException {
|
||||
// 获取微信支付的client对象
|
||||
WechatPayHttpClient client = WechatPayHttpClient.get();
|
||||
//请求地址
|
||||
String apiPath = StrUtil.format("/v3/pay/transactions/out-trade-no/{}/close", trading.getTradingOrderNo());
|
||||
//请求参数
|
||||
Map<String, Object> params = MapUtil.<String, Object>builder()
|
||||
.put("mchid", client.getMchId())
|
||||
.build();
|
||||
try {
|
||||
WeChatResponse response = client.doPost(apiPath, params);
|
||||
if (response.getStatus() == 204) {
|
||||
trading.setTradingState(TradingStateEnum.QXDD);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
} catch (Exception e) {
|
||||
throw new SLException(CLOSE_FAIL, e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Boolean refundTrading(RefundRecordEntity refundRecord) throws SLException {
|
||||
// 获取微信支付的client对象
|
||||
WechatPayHttpClient client = WechatPayHttpClient.get();
|
||||
//请求地址
|
||||
String apiPath = "/v3/refund/domestic/refunds";
|
||||
//请求参数
|
||||
Map<String, Object> params = MapUtil.<String, Object>builder()
|
||||
.put("out_refund_no", Convert.toStr(refundRecord.getRefundNo()))
|
||||
.put("out_trade_no", Convert.toStr(refundRecord.getTradingOrderNo()))
|
||||
.put("amount", MapUtil.<String, Object>builder()
|
||||
.put("refund", NumberUtil.mul(refundRecord.getRefundAmount(), 100)) //本次退款金额
|
||||
.put("total", NumberUtil.mul(refundRecord.getTotal(), 100)) //原订单金额
|
||||
.put("currency", "CNY") //币种
|
||||
.build())
|
||||
.build();
|
||||
WeChatResponse response;
|
||||
try {
|
||||
response = client.doPost(apiPath, params);
|
||||
} catch (Exception e) {
|
||||
log.error("调用微信接口出错!apiPath = {}, params = {}", apiPath, JSONUtil.toJsonStr(params), e);
|
||||
throw new SLException(NATIVE_REFUND_FAIL, e);
|
||||
}
|
||||
refundRecord.setRefundCode(Convert.toStr(response.getStatus()));
|
||||
refundRecord.setRefundMsg(response.getBody());
|
||||
if (response.isOk()) {
|
||||
JSONObject jsonObject = JSONUtil.parseObj(response.getBody());
|
||||
// SUCCESS:退款成功
|
||||
// CLOSED:退款关闭
|
||||
// PROCESSING:退款处理中
|
||||
// ABNORMAL:退款异常
|
||||
String status = jsonObject.getStr("status");
|
||||
if (StrUtil.equals(status, TradingConstant.WECHAT_REFUND_PROCESSING)) {
|
||||
refundRecord.setRefundStatus(RefundStatusEnum.SENDING);
|
||||
} else if (StrUtil.equals(status, TradingConstant.WECHAT_REFUND_SUCCESS)) {
|
||||
refundRecord.setRefundStatus(RefundStatusEnum.SUCCESS);
|
||||
} else {
|
||||
refundRecord.setRefundStatus(RefundStatusEnum.FAIL);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
throw new SLException(refundRecord.getRefundMsg(), NATIVE_REFUND_FAIL.getCode(), NATIVE_REFUND_FAIL.getStatus());
|
||||
}
|
||||
|
||||
@Override
|
||||
public Boolean queryRefundTrading(RefundRecordEntity refundRecord) throws SLException {
|
||||
// 获取微信支付的client对象
|
||||
WechatPayHttpClient client = WechatPayHttpClient.get();
|
||||
|
||||
//请求地址
|
||||
String apiPath = StrUtil.format("/v3/refund/domestic/refunds/{}", refundRecord.getRefundNo());
|
||||
|
||||
WeChatResponse response;
|
||||
try {
|
||||
response = client.doGet(apiPath);
|
||||
} catch (Exception e) {
|
||||
log.error("调用微信接口出错!apiPath = {}", apiPath, e);
|
||||
throw new SLException(NATIVE_QUERY_REFUND_FAIL, e);
|
||||
}
|
||||
|
||||
refundRecord.setRefundCode(Convert.toStr(response.getStatus()));
|
||||
refundRecord.setRefundMsg(response.getBody());
|
||||
if (response.isOk()) {
|
||||
JSONObject jsonObject = JSONUtil.parseObj(response.getBody());
|
||||
// SUCCESS:退款成功
|
||||
// CLOSED:退款关闭
|
||||
// PROCESSING:退款处理中
|
||||
// ABNORMAL:退款异常
|
||||
String status = jsonObject.getStr("status");
|
||||
if (StrUtil.equals(status, TradingConstant.WECHAT_REFUND_PROCESSING)) {
|
||||
refundRecord.setRefundStatus(RefundStatusEnum.SENDING);
|
||||
} else if (StrUtil.equals(status, TradingConstant.WECHAT_REFUND_SUCCESS)) {
|
||||
refundRecord.setRefundStatus(RefundStatusEnum.SUCCESS);
|
||||
} else {
|
||||
refundRecord.setRefundStatus(RefundStatusEnum.FAIL);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
throw new SLException(response.getBody(), NATIVE_QUERY_REFUND_FAIL.getCode(), NATIVE_QUERY_REFUND_FAIL.getStatus());
|
||||
}
|
||||
|
||||
}
|
@@ -0,0 +1,19 @@
|
||||
package com.sl.pay.handler.wechat;
|
||||
|
||||
import com.sl.pay.entity.TradingEntity;
|
||||
import com.sl.pay.handler.NativePayHandler;
|
||||
import com.sl.transport.common.exception.SLException;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
/**
|
||||
* 微信二维码支付
|
||||
*/
|
||||
@Component("wechatNativePayHandler")
|
||||
public class WechatNativePayHandler implements NativePayHandler {
|
||||
|
||||
@Override
|
||||
public void createDownLineTrading(TradingEntity tradingEntity) throws SLException {
|
||||
|
||||
}
|
||||
|
||||
}
|
@@ -0,0 +1,170 @@
|
||||
package com.sl.pay.handler.wechat;
|
||||
|
||||
import cn.hutool.core.net.url.UrlBuilder;
|
||||
import cn.hutool.core.net.url.UrlPath;
|
||||
import cn.hutool.core.net.url.UrlQuery;
|
||||
import cn.hutool.core.util.CharsetUtil;
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import cn.hutool.json.JSONUtil;
|
||||
import com.sl.pay.handler.wechat.response.WeChatResponse;
|
||||
import com.wechat.pay.contrib.apache.httpclient.auth.PrivateKeySigner;
|
||||
import com.wechat.pay.contrib.apache.httpclient.auth.WechatPay2Credentials;
|
||||
import com.wechat.pay.contrib.apache.httpclient.auth.WechatPay2Validator;
|
||||
import com.wechat.pay.contrib.apache.httpclient.cert.CertificatesManager;
|
||||
import com.wechat.pay.contrib.apache.httpclient.util.PemUtil;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Builder;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
import org.apache.http.client.methods.CloseableHttpResponse;
|
||||
import org.apache.http.client.methods.HttpGet;
|
||||
import org.apache.http.client.methods.HttpPost;
|
||||
import org.apache.http.entity.StringEntity;
|
||||
import org.apache.http.impl.client.CloseableHttpClient;
|
||||
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.net.URI;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.security.PrivateKey;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* 微信支付远程调用对象
|
||||
*/
|
||||
@Data
|
||||
@Builder
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
public class WechatPayHttpClient {
|
||||
|
||||
private String mchId; //商户号
|
||||
private String appId; //应用号
|
||||
private String privateKey; //私钥字符串
|
||||
private String mchSerialNo; //商户证书序列号
|
||||
private String apiV3Key; //V3密钥
|
||||
private String domain; //请求域名
|
||||
private String notifyUrl; //请求地址
|
||||
|
||||
public static WechatPayHttpClient get() {
|
||||
//通过渠道对象转化成微信支付的client对象
|
||||
return WechatPayHttpClient.builder()
|
||||
.appId("wx6592a2db3f85ed25")
|
||||
.domain("api.mch.weixin.qq.com")
|
||||
.privateKey("-----BEGIN PRIVATE KEY-----\n" +
|
||||
"MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQDBHGgIh80193Gh\n" +
|
||||
"dpD1LtMZfTRpcWI0fImyuBCyrd3gYb3rrsARebGcHdJsQA3mVjVqVp5ybhEZDPa4\n" +
|
||||
"ecoK4Ye1hTppNpI/lmLt4/uUV/zhF5ahli7hi+116Ty6svHSbuMQBuUZeTFOwGrx\n" +
|
||||
"jvofU/4pGIwh8ZvkcSnyOp9uX2177UVxDBkhgbZbJp9XF2b83vUa5eHo93CziPzn\n" +
|
||||
"3hFdAlBCdTXB7DH+m0nN3Jou0szGukvq7cIgGpHku4ycKSTkIhhl9WRhN6OoSEJx\n" +
|
||||
"q88MXzjkzTruc85PHN52aUTUifwg3T8Y4XqFQ61dTnEmgxeD2O6/pLdB9gLsp6yC\n" +
|
||||
"GqN5Lqk7AgMBAAECggEBAL4X+WzUSbSjFS9NKNrCMjm4H1zgqTxjj6TnPkC1mGEl\n" +
|
||||
"tjAHwLgzJBw62wWGdGhWWpSIGccpBBm1wjTMZpAZfF66fEpP1t1Ta6UjtGZNyvfF\n" +
|
||||
"IZmE3jdWZ/WXGBnsxtFQKKKBNwrBW0Fbdqq9BQjLxLitmlxbmwrgPttcy855j6vZ\n" +
|
||||
"qq4MBT1v8CtUT/gz4UWW2xWovVnmWOrRSScv7Nh0pMbRpPLkNHXrBwSSNz/keORz\n" +
|
||||
"XB9JSm85wlkafa7n5/IJbdTml3A/uAgW3q3JZZQotHxQsYvD4Zb5Cnc9CPAXE5L2\n" +
|
||||
"Yk877kVXZMGt5QPIVcPMj/72AMtaJT67Y0fN0RYHEGkCgYEA38BIGDY6pePgPbxB\n" +
|
||||
"7N/l6Df0/OKPP0u8mqR4Q0aQD3VxeGiZUN1uWXEFKsKwlOxLfIFIFk1/6zQeC0xe\n" +
|
||||
"tNTKk0gTL8hpMUTNkE7vI9gFWws2LY6DE86Lm0bdFEIwh6d7Fr7zZtyQKPzMsesC\n" +
|
||||
"3XV9sdSUExEi5o/VwAyf+xZlOXcCgYEA3PGZYlILjg3esPNkhDz2wxFw432i8l/B\n" +
|
||||
"CPD8ZtqIV9eguu4fVtFYcUVfawBb0T11RamJkc4eiSOqayC+2ehgb+GyRLJNK4Fq\n" +
|
||||
"bFcsIT+CK0HlscZw51jrMR0MxTc4RzuOIMoYDeZqeGB6/YnNyG4pw2sD8bIwHm84\n" +
|
||||
"06gtJsX/v10CgYAo8g3/aEUZQHcztPS3fU2cTkkl0ev24Ew2XGypmwsX2R0XtMSB\n" +
|
||||
"uNPNyFHyvkgEKK2zrhDcC/ihuRraZHJcUyhzBViFgP5HBtk7VEaM36YzP/z9Hzw7\n" +
|
||||
"bqu7kZ85atdoq6xpwC3Yn/o9le17jY8rqamD1mv2hUdGvAGYsHbCQxnpBwKBgHTk\n" +
|
||||
"eaMUBzr7yZLS4p435tHje1dQVBJpaKaDYPZFrhbTZR0g+IGlNmaPLmFdCjbUjiPy\n" +
|
||||
"A2+Znnwt227cHz0IfWUUAo3ny3419QkmwZlBkWuzbIO2mms7lwsf9G6uvV6qepKM\n" +
|
||||
"eVd5TWEsokVbT/03k27pQmfwPxcK/wS0GFdIL/udAoGAOYdDqY5/aadWCyhzTGI6\n" +
|
||||
"qXPLvC+fsJBPhK2RXyc+jYV0KmrEv4ewxlK5NksuFsNkyB7wlI1oMCa/xB3T/2vT\n" +
|
||||
"BALgGFPi8BJqceUjtnTYtI4R2JIVEl08RtEJwyU5JZ2rvWcilsotVZYwfuLZ9Kfd\n" +
|
||||
"hkTrgNxlp/KKkr+UuKce4Vs=\n" +
|
||||
"-----END PRIVATE KEY-----\n")
|
||||
.mchId("1561414331")
|
||||
.mchSerialNo("25FBDE3EFD31B03A4377EB9A4A47C517969E6620")
|
||||
.apiV3Key("CZBK51236435wxpay435434323FFDuv3")
|
||||
.notifyUrl("https://www.itcast.cn/")
|
||||
.build();
|
||||
}
|
||||
|
||||
/***
|
||||
* 构建CloseableHttpClient远程请求对象
|
||||
* @return org.apache.http.impl.client.CloseableHttpClient
|
||||
*/
|
||||
public CloseableHttpClient createHttpClient() throws Exception {
|
||||
// 加载商户私钥(privateKey:私钥字符串)
|
||||
PrivateKey merchantPrivateKey = PemUtil.loadPrivateKey(new ByteArrayInputStream(privateKey.getBytes(StandardCharsets.UTF_8)));
|
||||
|
||||
// 加载平台证书(mchId:商户号,mchSerialNo:商户证书序列号,apiV3Key:V3密钥)
|
||||
PrivateKeySigner privateKeySigner = new PrivateKeySigner(mchSerialNo, merchantPrivateKey);
|
||||
WechatPay2Credentials wechatPay2Credentials = new WechatPay2Credentials(mchId, privateKeySigner);
|
||||
|
||||
// 向证书管理器增加需要自动更新平台证书的商户信息
|
||||
CertificatesManager certificatesManager = CertificatesManager.getInstance();
|
||||
certificatesManager.putMerchant(mchId, wechatPay2Credentials, apiV3Key.getBytes(StandardCharsets.UTF_8));
|
||||
|
||||
// 初始化httpClient
|
||||
return com.wechat.pay.contrib.apache.httpclient.WechatPayHttpClientBuilder.create()
|
||||
.withMerchant(mchId, mchSerialNo, merchantPrivateKey)
|
||||
.withValidator(new WechatPay2Validator(certificatesManager.getVerifier(mchId)))
|
||||
.build();
|
||||
}
|
||||
|
||||
/***
|
||||
* 支持post请求的远程调用
|
||||
*
|
||||
* @param apiPath api地址
|
||||
* @param params 携带请求参数
|
||||
* @return 返回字符串
|
||||
*/
|
||||
public WeChatResponse doPost(String apiPath, Map<String, Object> params) throws Exception {
|
||||
String url = StrUtil.format("https://{}{}", this.domain, apiPath);
|
||||
HttpPost httpPost = new HttpPost(url);
|
||||
httpPost.addHeader("Accept", "application/json");
|
||||
httpPost.addHeader("Content-type", "application/json; charset=utf-8");
|
||||
|
||||
String body = JSONUtil.toJsonStr(params);
|
||||
httpPost.setEntity(new StringEntity(body, CharsetUtil.UTF_8));
|
||||
|
||||
CloseableHttpResponse response = this.createHttpClient().execute(httpPost);
|
||||
return new WeChatResponse(response);
|
||||
}
|
||||
|
||||
/***
|
||||
* 支持get请求的远程调用
|
||||
* @param apiPath api地址
|
||||
* @param params 在路径中请求的参数
|
||||
* @return 返回字符串
|
||||
*/
|
||||
public WeChatResponse doGet(String apiPath, Map<String, Object> params) throws Exception {
|
||||
URI uri = UrlBuilder.create()
|
||||
.setHost(this.domain)
|
||||
.setScheme("https")
|
||||
.setPath(UrlPath.of(apiPath, CharsetUtil.CHARSET_UTF_8))
|
||||
.setQuery(UrlQuery.of(params))
|
||||
.setCharset(CharsetUtil.CHARSET_UTF_8)
|
||||
.toURI();
|
||||
return this.doGet(uri);
|
||||
}
|
||||
|
||||
/***
|
||||
* 支持get请求的远程调用
|
||||
* @param apiPath api地址
|
||||
* @return 返回字符串
|
||||
*/
|
||||
public WeChatResponse doGet(String apiPath) throws Exception {
|
||||
URI uri = UrlBuilder.create()
|
||||
.setHost(this.domain)
|
||||
.setScheme("https")
|
||||
.setPath(UrlPath.of(apiPath, CharsetUtil.CHARSET_UTF_8))
|
||||
.setCharset(CharsetUtil.CHARSET_UTF_8)
|
||||
.toURI();
|
||||
return this.doGet(uri);
|
||||
}
|
||||
|
||||
private WeChatResponse doGet(URI uri) throws Exception {
|
||||
HttpGet httpGet = new HttpGet(uri);
|
||||
httpGet.addHeader("Accept", "application/json");
|
||||
CloseableHttpResponse response = this.createHttpClient().execute(httpGet);
|
||||
return new WeChatResponse(response);
|
||||
}
|
||||
|
||||
}
|
@@ -0,0 +1,31 @@
|
||||
package com.sl.pay.handler.wechat.response;
|
||||
|
||||
import cn.hutool.core.util.CharsetUtil;
|
||||
import lombok.Data;
|
||||
import org.apache.http.client.methods.CloseableHttpResponse;
|
||||
import org.apache.http.util.EntityUtils;
|
||||
|
||||
@Data
|
||||
public class WeChatResponse {
|
||||
|
||||
private int status; //响应状态码
|
||||
private String body; //响应体数据
|
||||
|
||||
public WeChatResponse() {
|
||||
|
||||
}
|
||||
|
||||
public WeChatResponse(CloseableHttpResponse response) {
|
||||
this.status = response.getStatusLine().getStatusCode();
|
||||
try {
|
||||
this.body = EntityUtils.toString(response.getEntity(), CharsetUtil.UTF_8);
|
||||
} catch (Exception e) {
|
||||
// 如果出现异常,响应体为null
|
||||
}
|
||||
}
|
||||
|
||||
public Boolean isOk() {
|
||||
return this.status == 200;
|
||||
}
|
||||
|
||||
}
|
19
sl-express-pay/src/main/resources/bootstrap.yml
Normal file
19
sl-express-pay/src/main/resources/bootstrap.yml
Normal file
@@ -0,0 +1,19 @@
|
||||
server:
|
||||
port: 18099
|
||||
tomcat:
|
||||
uri-encoding: UTF-8
|
||||
threads:
|
||||
max: 1000
|
||||
min-spare: 30
|
||||
spring:
|
||||
application:
|
||||
name: sl-express-pay
|
||||
mvc:
|
||||
pathmatch:
|
||||
#解决异常:swagger Failed to start bean 'documentationPluginsBootstrapper'; nested exception is java.lang.NullPointerException
|
||||
#因为Springfox使用的路径匹配是基于AntPathMatcher的,而Spring Boot 2.6.X使用的是PathPatternMatcher
|
||||
matching-strategy: ant_path_matcher
|
||||
redis: #redis的配置
|
||||
port: 6379
|
||||
host: 192.168.150.101
|
||||
password: 123321
|
@@ -0,0 +1,56 @@
|
||||
package com.sl.pay.handler.alipay;
|
||||
|
||||
import com.sl.pay.entity.RefundRecordEntity;
|
||||
import com.sl.pay.entity.TradingEntity;
|
||||
import com.sl.pay.handler.BasicPayHandler;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.springframework.boot.test.context.SpringBootTest;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
import java.math.BigDecimal;
|
||||
|
||||
@SpringBootTest
|
||||
class AliBasicPayHandlerTest {
|
||||
|
||||
@Resource(name = "aliBasicPayHandler")
|
||||
BasicPayHandler basicPayHandler;
|
||||
|
||||
@Test
|
||||
void queryTrading() {
|
||||
TradingEntity tradingEntity = new TradingEntity();
|
||||
tradingEntity.setTradingOrderNo(11223388L); //交易单号
|
||||
Boolean result = this.basicPayHandler.queryTrading(tradingEntity);
|
||||
System.out.println("执行是否成功:" + result);
|
||||
System.out.println(tradingEntity);
|
||||
}
|
||||
|
||||
@Test
|
||||
void closeTrading() {
|
||||
TradingEntity tradingEntity = new TradingEntity();
|
||||
tradingEntity.setTradingOrderNo(11223377L); //交易单号
|
||||
Boolean result = this.basicPayHandler.closeTrading(tradingEntity);
|
||||
System.out.println("执行是否成功:" + result);
|
||||
System.out.println(tradingEntity);
|
||||
}
|
||||
|
||||
@Test
|
||||
void refundTrading() {
|
||||
RefundRecordEntity refundRecordEntity = new RefundRecordEntity();
|
||||
refundRecordEntity.setTradingOrderNo(11223388L); //交易单号
|
||||
refundRecordEntity.setRefundNo(11223380L); //退款单号
|
||||
refundRecordEntity.setRefundAmount(BigDecimal.valueOf(0.1)); //退款金额
|
||||
Boolean result = this.basicPayHandler.refundTrading(refundRecordEntity);
|
||||
System.out.println("执行是否成功:" + result);
|
||||
System.out.println(refundRecordEntity);
|
||||
}
|
||||
|
||||
@Test
|
||||
void queryRefundTrading() {
|
||||
RefundRecordEntity refundRecordEntity = new RefundRecordEntity();
|
||||
refundRecordEntity.setTradingOrderNo(11223388L); //交易单号
|
||||
refundRecordEntity.setRefundNo(11223388L); //退款单号
|
||||
Boolean result = this.basicPayHandler.queryRefundTrading(refundRecordEntity);
|
||||
System.out.println("执行是否成功:" + result);
|
||||
System.out.println(refundRecordEntity);
|
||||
}
|
||||
}
|
@@ -0,0 +1,32 @@
|
||||
package com.sl.pay.handler.alipay;
|
||||
|
||||
import com.sl.pay.entity.TradingEntity;
|
||||
import com.sl.pay.handler.NativePayHandler;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.springframework.boot.test.context.SpringBootTest;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.*;
|
||||
|
||||
@SpringBootTest
|
||||
class AliNativePayHandlerTest {
|
||||
|
||||
@Resource(name = "aliNativePayHandler")
|
||||
NativePayHandler nativePayHandler;
|
||||
|
||||
@Test
|
||||
void createDownLineTrading() {
|
||||
TradingEntity tradingEntity = new TradingEntity();
|
||||
tradingEntity.setProductOrderNo(12345L); //订单号
|
||||
tradingEntity.setTradingOrderNo(11223388L); //交易单号
|
||||
tradingEntity.setMemo("运费");
|
||||
tradingEntity.setTradingAmount(BigDecimal.valueOf(1));
|
||||
this.nativePayHandler.createDownLineTrading(tradingEntity);
|
||||
|
||||
System.out.println("二维码信息:" + tradingEntity.getPlaceOrderMsg());
|
||||
System.out.println(tradingEntity);
|
||||
}
|
||||
}
|
@@ -0,0 +1,59 @@
|
||||
package com.sl.pay.handler.wechat;
|
||||
|
||||
import com.sl.pay.entity.RefundRecordEntity;
|
||||
import com.sl.pay.entity.TradingEntity;
|
||||
import com.sl.pay.handler.BasicPayHandler;
|
||||
import com.sl.pay.handler.alipay.AliBasicPayHandler;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.springframework.boot.test.context.SpringBootTest;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
import java.math.BigDecimal;
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
@SpringBootTest
|
||||
class WechatBasicPayHandlerTest {
|
||||
|
||||
@Resource(name = "weChatBasicPayHandler")
|
||||
BasicPayHandler basicPayHandler;
|
||||
|
||||
@Test
|
||||
void queryTrading() {
|
||||
TradingEntity tradingEntity = new TradingEntity();
|
||||
tradingEntity.setTradingOrderNo(11223388L); //交易单号
|
||||
tradingEntity.setCreated(LocalDateTime.now());
|
||||
Boolean result = this.basicPayHandler.queryTrading(tradingEntity);
|
||||
System.out.println("执行是否成功:" + result);
|
||||
System.out.println(tradingEntity);
|
||||
}
|
||||
|
||||
@Test
|
||||
void closeTrading() {
|
||||
TradingEntity tradingEntity = new TradingEntity();
|
||||
tradingEntity.setTradingOrderNo(11223377L); //交易单号
|
||||
Boolean result = this.basicPayHandler.closeTrading(tradingEntity);
|
||||
System.out.println("执行是否成功:" + result);
|
||||
System.out.println(tradingEntity);
|
||||
}
|
||||
|
||||
@Test
|
||||
void refundTrading() {
|
||||
RefundRecordEntity refundRecordEntity = new RefundRecordEntity();
|
||||
refundRecordEntity.setTradingOrderNo(11223388L); //交易单号
|
||||
refundRecordEntity.setRefundNo(11223380L); //退款单号
|
||||
refundRecordEntity.setRefundAmount(BigDecimal.valueOf(0.1)); //退款金额
|
||||
Boolean result = this.basicPayHandler.refundTrading(refundRecordEntity);
|
||||
System.out.println("执行是否成功:" + result);
|
||||
System.out.println(refundRecordEntity);
|
||||
}
|
||||
|
||||
@Test
|
||||
void queryRefundTrading() {
|
||||
RefundRecordEntity refundRecordEntity = new RefundRecordEntity();
|
||||
refundRecordEntity.setTradingOrderNo(11223388L); //交易单号
|
||||
refundRecordEntity.setRefundNo(11223388L); //退款单号
|
||||
Boolean result = this.basicPayHandler.queryRefundTrading(refundRecordEntity);
|
||||
System.out.println("执行是否成功:" + result);
|
||||
System.out.println(refundRecordEntity);
|
||||
}
|
||||
}
|
@@ -0,0 +1,32 @@
|
||||
package com.sl.pay.handler.wechat;
|
||||
|
||||
import com.sl.pay.entity.TradingEntity;
|
||||
import com.sl.pay.handler.NativePayHandler;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.springframework.boot.test.context.SpringBootTest;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.*;
|
||||
|
||||
@SpringBootTest
|
||||
class WechatNativePayHandlerTest {
|
||||
|
||||
@Resource(name = "wechatNativePayHandler")
|
||||
NativePayHandler nativePayHandler;
|
||||
|
||||
@Test
|
||||
void createDownLineTrading() {
|
||||
TradingEntity tradingEntity = new TradingEntity();
|
||||
tradingEntity.setProductOrderNo(12345L); //订单号
|
||||
tradingEntity.setTradingOrderNo(11223388L); //交易单号
|
||||
tradingEntity.setMemo("运费");
|
||||
tradingEntity.setTradingAmount(BigDecimal.valueOf(1));
|
||||
this.nativePayHandler.createDownLineTrading(tradingEntity);
|
||||
|
||||
System.out.println("二维码信息:" + tradingEntity.getPlaceOrderMsg());
|
||||
System.out.println(tradingEntity);
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user