Skip to content

聚合支付

获取所有支付渠道

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);
    }

广州宝点数字化科技