Appearance
聚合支付
获取所有支付渠道
c#
private readonly IPaymentFactory _paymentFactory;
public PaymentFactoryController()
{
_paymentFactory = IocManager.Instance.RootServices.GetRequiredService<IPaymentFactory>();
}
[HttpGet("list")]
public async Task<CallResult<List<IPaymentChannel>>> TestPaymentFactoryAsync()
{
var channels = _paymentFactory.GetAllPaymentChannels();
return await Task.FromResult(CallResult.Ok(channels));
}获取指定支付渠道
c#
var channels = _paymentFactory.GetPaymentChannel("Saobei", settingJson);国内-通用支付
刷卡支付(即客户被扫支付)
c#
[Test]
public void TestSwipeCard()
{
SwipeCardContext context = new();
context.Attach = Guid.NewGuid().ToString();
context.BusinessTime = DateTime.Now;
context.OrderBody = "";
context.PaymentType = EnumPaymentType.Auto;
context.QrCode = qrcode;
context.TerminalIp = "127.0.0.1";
context.TerminalLocation = "";
context.TerminalTrace = orderNO;
context.TotalFee = 1;
context.WechatSubAppId = "";
var result = channel.SwipePay(context);
// 判断支付结果
}主扫支付(即客户主扫支付)
c#
小程序支付
c#
MiniPayContext context = new()
{
WechatSubAppId = MerchantInfo.AppId,
OpenId = MerchantInfo.OpenId,
PaymentType = EnumPaymentType.Wechat,
NotifyUrl = "",
TotalFee = 1,
TerminalIp = "127.0.0.1",
TerminalLocation = "",
TerminalTrace = orderNO,
OrderBody = "",
Attach = "",
};
var result = executor.MiniPay(context);H5支付
在微信 和 支付宝的浏览器窗口中打开H5页面,然后调起微信或支付宝的支付。
c#
[Test]
public void Test_JS支付_支付宝H5()
{
// 用户输入
var orderNO = DateTime.Now.ToString("yyyyMMddHHmmssfffff");
var aliBuyerId = "2088002626454922";
// 获取支付渠道
var channel = _paymentFactory.CreateChannel(MerchantInfo.ChannelCode, _settingJson);
var executor = channel.GetPaymentExecutor(MerchantInfo.ExecuteCode);
Assert.IsNotNull(executor);
// 小程序支付
{
JsPayContext context = new()
{
JsPaymentType = EnumJsPaymentType.支付宝H5,
Amount = 1,
MerchantTradeNO = orderNO,
AliBuyerId = aliBuyerId,
GoodsDesc = "测试商品",
ValidSeconds = 5 * 60,
NotifyUrl = "https://md.bdszh.jingjianx.vip/payment/huifu/callback",
};
var result = executor!.JsPay(context);
Debug.WriteLine($"JS支付:支付结果:{result.ResultType}");
Debug.WriteLine($"JS支付:订单号:{orderNO}");
}
}查询订单
[Test] public void TestQueryOrder() { QueryOrderContext context = new(); context.OutTradeNO = orderNO; context.PaymentType = EnumPaymentType.Auto;
var result = channel.QueryOrder(context);
// 查询订单结果
}
c#
订单退款
c#
[Test]
public void TestRefund()
{
RefundContext context = new();
context.OutTradeNO = "2023062820424147298";
context.PaymentType = EnumPaymentType.Auto;
context.RefundOrderNO = DateTime.Now.ToString("yyyyMMddHHmmssfffff");
context.RefundFee = 1;
var channel = _paymentFactory.CreateChannel(_channelNO, _setting.ToJsonString());
var result = channel.Refund(context);
}取消订单
c#
[Test]
public void TestCannel()
{
CancelContext context = new();
context.OutTradeNO = "2023062820424147298";
context.PaymentType = EnumPaymentType.Auto;
var channel = _paymentFactory.CreateChannel(_channelNO, _setting.ToJsonString());
var result = channel.Cancel(context);
}支付回调
c#
[Test]
public void Test_回调验签()
{
// 获取支付渠道
var channel = _paymentFactory.CreateChannel(MerchantInfo.ChannelCode, _settingJson);
var executor = channel.GetPaymentExecutor(MerchantInfo.ExecuteCode);
PayCallbackContext context = new() { HttpContext = HttpContext };
var result = executor!.PayCallbackAsync(context).Result;
// 自有业务代码
// ...
if (result.ResultType == PayCallbackResultType.支付成功)
{
executor.PayCallbackResponseSuccessAsync(HttpContext).Wait();
}
else executor.PayCallbackResponseFailureAsync(HttpContext).Wait();
}国内-余额分账
余额分账
c#
[Test]
public void Test_余额归集()
{
BalanceAllocateContext context = new();
context.MerchantTradeNO = DateTime.Now.ToString("yyyyMMddHHmmssfffff");
context.Attach = "123";
context.Amount = 1;
context.NotifyUrl = "http://xxxxx.jingjianx.vip/allocate/callback";
context.OutMerchantNO = MerchantInfo.MerchantNO;
context.InMerchantNOCBK = "00000000000000000"; // 此处扫呗为CBK账号
var channel = _paymentFactory.CreateChannel(MerchantInfo.ChannelCode, _settingJson);
var executor = channel.GetPaymentExecutor(MerchantInfo.ExecuteCode);
Assert.IsNotNull(executor);
var result = executor.BalanceAllocate(context);
Debug.WriteLine($"归集订单号:{context.MerchantTradeNO}");
Debug.WriteLine($"出账商户号:{context.OutMerchantNO}");
Debug.WriteLine($"入账CBK商户号:{context.InMerchantNOCBK}");
Debug.WriteLine($"平台端分账订单号:{result.PlatformAllocateTradeNO}");
Assert.IsTrue(result.ResultType == BalanceAllocateResultType.分账成功 || result.ResultType == BalanceAllocateResultType.处理中);
}余额分账查询
c#
[Test]
public void Test_余额归集查询()
{
BalanceAllocateQueryContext context = new();
context.PlatformAllocateTradeNO = "00000000000000000000"; // 平台端分账订单号
var channel = _paymentFactory.CreateChannel(MerchantInfo.ChannelCode, _settingJson);
var executor = channel.GetPaymentExecutor(MerchantInfo.ExecuteCode);
Assert.IsNotNull(executor);
var result = executor.BalanceAllocateQuery(context);
// 查询退款结果
Assert.IsTrue(result.ResultType != BalanceAllocateQueryResultType.未知);
}余额分账退回
c#
[Test]
public void Test_余额归集退款()
{
BalanceAllocateRefundContext context = new();
context.MerchantRefundTradeNO = DateTime.Now.ToString("yyyyMMddHHmmssfffff");
context.PlatformAllocateTradeNO = "603324903205325111011362016813";
context.Attach = "123";
context.RefundAmount = 1;
var channel = _paymentFactory.CreateChannel(MerchantInfo.ChannelCode, _settingJson);
var executor = channel.GetPaymentExecutor(MerchantInfo.ExecuteCode);
Assert.IsNotNull(executor);
var result = executor.BalanceAllocateRefund(context);
Assert.IsTrue(result.ResultType == BalanceAllocateRefundResultType.退回成功);
}余额分账结果回调
c#
[Test]
public void Test_解析余额归集商户订单号()
{
var merchantTradeNO = SaobeiPaymentChannel.ResloveBalanceAllocateCallbackMerchantTradeNO(httpContext);
Assert.IsTrue(merchantTradeNO.Length > 0);
}
[Test]
public void Test_余额归集回调通知()
{
var channel = _paymentFactory.CreateChannel(MerchantInfo.ChannelCode, _settingJson);
var executor = channel.GetPaymentExecutor(MerchantInfo.ExecuteCode);
Assert.IsNotNull(executor);
// 获取回调的数据
var result = executor.BalanceAllocateCallback(new BalanceAllocateCallbackContext(){ HttpContext = httpContext });
if (执行业务逻辑成功)
{
executor.BalanceAllocateCallbackResponseSuccess(httpContext);
}
else executor.BalanceAllocateCallbackResponseFailure(httpContext, "内部处理失败");
}国际-POS机支付
远程调起POS机支付模式
POS机支付
c#
[Test]
public void Test_Pos支付()
{
var merchantTradeNo = DateTime.Now.ToString("yyyyMMddHHmmssfffff");
// 获取支付渠道
var channel = _paymentFactory.CreateChannel(MerchantInfo.ChannelCode, _settingJson);
var executor = channel.GetPaymentExecutor(MerchantInfo.ExecuteCode);
PosPayContext context = new()
{
TerminalNO = TerminalId, // 终端ID
MerchantTradeNO = merchantTradeNo, // 商户订单号
Attach = Guid.NewGuid().ToString(), // 附加数据
OrderBody = "", // 订单详情
TotalFee = 1, // 金额,单位分
NotifyUrl = "http://xxxx.com/saobeipos/callback", // 回调地址
};
context.ExtendParameters.Add("XPairId", XPairId); // 配对ID,仅用于Bonus(蒙古)支付
var result = executor!.PosPay(context);
Debug.WriteLine($"反扫支付:结果:{result.ResultType}:{result.Msg}");
Debug.WriteLine($"反扫支付:商户订单号:{merchantTradeNo}");
Assert.IsTrue(result.ResultType == PosPayResultType.预支付成功);
}POS机关单
取消当前POS机正在执行的操作
c#
[Test]
public void Test_Pos关单()
{
// 获取支付渠道
var channel = _paymentFactory.CreateChannel(MerchantInfo.ChannelCode, _settingJson);
var executor = channel.GetPaymentExecutor(MerchantInfo.ExecuteCode);
PosCloseContext context = new();
context.TerminalNO = "000001"; // 终端ID
context.ExtendParameters.Add("XPairId", XPairId); // 配对ID,仅用于Bonus(蒙古)支付
var result = executor!.PosClose(context);
}POS订单查询
查询POS机订单状态
c#
[Test]
public void Test_Pos查询_商户订单号()
{
var merchantTradeNo = "P01325641757672131403688";
// 获取支付渠道
var channel = _paymentFactory.CreateChannel(MerchantInfo.ChannelCode, _settingJson);
var executor = channel.GetPaymentExecutor(MerchantInfo.ExecuteCode);
PosQueryContext context = new()
{
TerminalNO = TerminalId,
MerchantTradeNO = merchantTradeNo, // 商家订单号
PlatformTradeNO = "17171890:68c4d0f5270a09a2bc920e54b62d9e54", // 平台订单号
TotalFee = 750,
};
context.ExtendParameters.Add("XPairId", XPairId); // 配对ID,仅用于Bonus(蒙古)支付
var result = executor!.PosQuery(context);
}POS订单退款
POS机已支付的订单,进行退款处理,根据订单状态会包含两个操作:Void或者Refund二选一
c#
[Test]
public void Test_Pos退款()
{
var context = new PosRefundContext()
{
TerminalNO = "C081UG43363266", // 终端编号 或 硬件编号
PosPayType = PosPayType.EDC, // 刷卡或扫码
MerchantTradeNO = "", // 商户订单号
MerchantTradeTime = DateTime.Now.Date, // 商户订单交易时间
RefundMerchantTradeNO = DateTime.Now.ToString("yyyyMMddHHmmssfffff"), // 商户退款订单号
RefundMerchantTradeTime = DateTime.Now, // 商户退款时间
TotalAmount = 1, // 订单总金额,单位分
RefundAmount = 1, // 退款金额,单位分
OrderBody = "测试订单", // 订单描述
};
var result = _executor.PosRefund(context);
}
支付渠道支持
国内支付渠道支持
以下支持/不支持,仅代表代码已实现或未实现,不代表渠道能力。
| 渠道名称 | 反扫接口 | 正扫接口 | H5接口 | 小程序支付接口 | 支付回调 | 余额分账 | 余额分账回调 |
|---|---|---|---|---|---|---|---|
| 扫呗 | 支持 | 支持 | 不支持 | 支持 | 支持 | 支持 | 支持 |
| 汇付 | 支持 | 支持 | 支持 | 支持 | 支持 | 支持 | 支持 |
| 斗拱 | 支持 | 支持 | 不支持 | 支持 | 支持 | 不支持 | 不支持 |
| 富友 | 支持 | 支持 | 不支持 | 支持 | 支持 | 不支持 | 不支持 |
| 拉卡拉 | 支持 | 支持 | 不支持 | 支持 | 不支持 | 不支持 | 不支持 |
国际支付渠道支持
以下支持/不支持,仅代表代码已实现或未实现,不代表渠道能力。
| 渠道名称 | 反扫接口 | 正扫接口 | 支付回调 | PC-WEB | 发票对接 |
|---|---|---|---|---|---|
| 乐摇摇国际 | 支持 | 支持 | 支持 | 支持 | 不支持 |
| 扫呗国际 | 支持 | 支持 | 支持 | 支持 | 不支持 |
| Paypal | 不支持 | 不支持 | 不支持 | 支持 | 不支持 |
| Bonus(蒙古) | 支持 | 支持 | 支持 | 支持 | 支持 |
| Verifacti(西班牙) | 不支持 | 不支持 | 不支持 | 不支持 | 支持 |
国际POS机支持
以下支持/不支持,仅代表代码已实现或未实现,不代表渠道能力。
| 渠道名称 | POS支付 | POS退款 | 发票对接 |
|---|---|---|---|
| 扫呗国际 | 支持 | 支持 | 不支持 |
| FirstData(PAX) | 支持 | 支持 | 不支持 |
| Quackade(PAX) | 支持 | 支持 | 不支持 |
| Bonum(蒙古) | 支持 | 支持 | 支持 |
| ZBS | 支持 | 支持 | 不支持 |
实验性
由于海外支付 和 海外POS支付不熟悉,无法抽象出通用的支付接口,可先调用此临时方案。
注:后续该接口可能会调整。
Paywizard 支付SDK
字段解析:
TerminalId:终端ID,由渠道商分配
TerminalSn:终端序列号,POS机打印仓内部
PosId:商家端定义,与TerminalId一对一
注:绑定成功后,后续调用支付接口时,TerminalNO 传 PosId
c#
// 绑定终端
[Test]
public void Test_绑定终端()
{
// TerminalId:终端ID,由渠道商分配
// TerminalSn:终端序列号,由渠道商分配
// PosId:自己配置,和TerminalId一对一
var result = PaywizardPosSdk.TerminalBindAsync(_settingJson, MerchantInfo.TerminalId, MerchantInfo.TerminalSn, MerchantInfo.PosId).Result;
Assert.IsTrue(result.Success);
}
// 查询终端绑定关系
[Test]
public void Test_查询终端()
{
var result = PaywizardPosSdk.TerminalQueryAsync(_settingJson).Result;
Assert.IsTrue(result.Success);
}
// 解除绑定终端
[Test]
public void Test_解绑终端()
{
// TerminalId:终端ID,由渠道商分配
// PosId:自己配置,和TerminalId一对一
var result = PaywizardPosSdk.TerminalUnBindAsync(_settingJson, MerchantInfo.TerminalId, MerchantInfo.PosId).Result;
Assert.IsTrue(result.Success);
}