最近在做第三方支付功能,其中支付宝用了条码支付这种高大上的新支付方式,话说还有比较常见的是支付宝扫码支付,这两种有什么区别呢,很简单,就是扫码支付是消费者用手机主动扫码再支付,条码支付是商家用扫码枪主动扫码再支付。那么为何选择条码支付呢,因为这个速度快,从扫消费者手机上的条码或二维码,到支付完成,那是瞬间的事,不过要是触发了需要密码的时候,还是需要消费者在手机上输入支付密码后才能完成消费的。
介绍完了条码支付后,给个文档接口吧:支付宝条码支付。条码支付整个流程主要需要的API包含:支付接口alipay.trade.pay,查询订单接口alipay.trade.query,撤销订单接口alipay.trade.cancel,申请退款接口alipay.trade.refund。这些东西都在支付宝提供的SDK里面包含了,我们就不用重新造轮子了,支付宝已经提供了很好很强大的SDK了,只是这个生成的dll有点大。
那么要想使用这个功能,首先是需要一个支付宝商家账号的,这个是前置条件。然后需要设置好APPID,这个可以到这个网址获取支付宝APPID,获取好之后,还需要用OPENSSL软件生成RSA公钥和私钥,OPENSSL软件下载地址我也贴出来吧:OPENSSL的Windows版,32位的和64位的系统都可以用Win32 OpenSSL v1.0.2d Light。安装完之后先用genrsa -out {0} 1024生成私钥,其中{0}填私钥名称,可以携带绝对路径,再用rsa -in {0} -pubout -out {1}生成对应的公钥,其中{0}对应先生成的私钥,{1}对应要生成的公钥。生成完之后再到这个网址配置公钥:配置支付宝公钥。
大致流程就是这样,现在贴出各API我的调用示例吧:
条码支付请求:
/// <summary>
/// 扣款
/// </summary>
/// <param name="payLog">支付日志</param>
/// <returns></returns>
public void Pay(Mall_PayLog payLog)
{
//参考API列表-条码支付请求API https://app.alipay.com/market/document.htm?name=tiaomazhifu#page-11
var bizContent = new JsonObject();
//商户订单号
bizContent.Put("out_trade_no", payLog.OrderMain.OrderNum);
//场景:条码支付
bizContent.Put("scene", "bar_code");
//条码
bizContent.Put("auth_code", payLog.Summary);
//支付金额
bizContent.Put("total_amount", payLog.Money.ToString("F"));
//订单标题
bizContent.Put("subject", "当面付条码支付");
//商户操作员编号
bizContent.Put("operator_id", LoginContext.AuthSession.Emp.RealName);
//过期时间,默认5分钟后自动取消支付
bizContent.Put("time_expire", DateTime.Now.AddMinutes(5).ToString("yyyy-MM-dd HH:mm:ss"));
var payRequest = new AlipayTradePayRequest { BizContent = bizContent.ToString() };
var result = GetAopClient(payLog.PayType.PaySetting).Execute(payRequest);
switch (result.Code)
{
//支付成功
case ResultCode.SUCCESS:
payLog.IDNum = result.TradeNo;
payLog.PayedMoney = payLog.Money;
payLog.PayState = Mall_EnumPayLogState.Payed;
payLog.Update();
break;
//支付中
case ResultCode.INRROCESS:
payLog.IDNum = result.TradeNo;
payLog.Update();
throw new MallException(ExceptionCode.PAY_PAYING, "请在手机端确认支付");
//支付失败
default:
//payLog.IDNum = result.TradeNo;
//payLog.Update();
new Loger().Info(string.Format("支付宝支付失败,PayLogID:{0},交易号{1},错误信息:{2}", payLog.ID, result.TradeNo, result.SubMsg));
throw new MallException(ExceptionCode.PAY_NOTCOMPLETED, "支付宝条码支付失败:" + result.SubMsg);
}
}
查询订单:
/// <summary>
/// 服务端查询支付状态
/// </summary>
/// <returns>0:进行中,1:已完成,2:已取消</returns>
public int GetServicePayState(Mall_PayLog payLog)
{
var bizContent = new JsonObject();
//商户订单号(也可以只传支付宝交易号trade_no)
bizContent.Put("out_trade_no", payLog.OrderMain.OrderNum);
var payRequest = new AlipayTradeQueryRequest { BizContent = bizContent.ToString() };
var result = GetAopClient(payLog.PayType.PaySetting).Execute(payRequest);
switch (result.Code)
{
//处理成功
case ResultCode.SUCCESS:
if (result.TradeStatus == "TRADE_SUCCESS")
{
if (payLog.PayState == Mall_EnumPayLogState.Paying)
{
//更新支付状态
payLog.PayedMoney = payLog.Money;
payLog.PayState = Mall_EnumPayLogState.Payed;
payLog.Update();
}
return 1;
}
return 0;
default:
//备注保存失败信息
payLog.Summary = result.SubMsg;
payLog.Update();
return 2;
}
}
撤销订单:
/// <summary>
/// 撤销支付(撤销还未支付的付款)
/// </summary>
/// <param name="payLog"></param>
/// <returns></returns>
public void ReversePay(Mall_PayLog payLog)
{
var bizContent = new JsonObject();
//商户订单号
bizContent.Put("out_trade_no", payLog.OrderMain.OrderNum);
var payRequest = new AlipayTradeCancelRequest { BizContent = bizContent.ToString() };
var result = GetAopClient(payLog.PayType.PaySetting).Execute(payRequest);
switch (result.Code)
{
//撤销订单成功
case ResultCode.SUCCESS:
break;
default:
throw new MallException(ExceptionCode.PAY_NOTCOMPLETED, "撤销订单失败:" + result.SubMsg);
}
}
申请退款:
/// <summary>
/// 退款
/// </summary>
/// <param name="tradeNo">支付宝交易号</param>
/// <param name="refundAmount">退款金额</param>
/// <param name="appId">支付宝APPID</param>
/// <returns></returns>
public void RefundPay(string tradeNo, decimal refundAmount, string appId)
{
if (string.IsNullOrEmpty(tradeNo))
{
throw new MallException(ExceptionCode.COMMON_BASE_CODEERROR, "未找到支付宝交易号");
}
if (refundAmount < 0)
{
throw new MallException(ExceptionCode.COMMON_BASE_CODEERROR, "退款金额不能小于0");
}
if (string.IsNullOrEmpty(appId))
{
throw new MallException(ExceptionCode.COMMON_BASE_CODEERROR, "未找到支付宝AppId");
}
var bizContent = new JsonObject();
//支付宝交易号
bizContent.Put("trade_no", tradeNo);
//退款金额
bizContent.Put("refund_amount", refundAmount.ToString("F"));
//退款原因
bizContent.Put("refund_reason", "O2O当面付退款");
var payRequest = new AlipayTradeRefundRequest { BizContent = bizContent.ToString() };
var result = GetAopClient(appId).Execute(payRequest);
switch (result.Code)
{
//退款成功
case ResultCode.SUCCESS:
break;
//退款失败
default:
throw new MallException(ExceptionCode.PAY_NOTCOMPLETED, "退款失败:" + result.SubMsg);
}
}
需要特殊处理的是,当需要消费者在手机端输入支付密钥时,必须等待消费者输完密码完成支付后手动查询支付的最新状态,这个也可以做成自动刷新状态,我是做成手动刷新的,还有就是密钥的生成需要四个dll,在安装的openssl目录里找到
这四个dll放到你的程序根目录下就可以了,然后生成密钥就用这个函数:
/// <summary>
/// 执行OpenSsl命令
/// </summary>
/// <param name="commands">命令</param>
public void ExecuteOpenSslCommand(params string[] commands)
{
using (var openssl = new Process
{
StartInfo =
{
//设定程序名
FileName = _openSslPath,
//关闭Shell的使用
UseShellExecute = false,
//重定向标准输入
RedirectStandardInput = true,
//重定向标准输出
RedirectStandardOutput = true,
//重定向错误输出
RedirectStandardError = true,
//设置不显示窗口
CreateNoWindow = true
}
})
{
openssl.Start();
commands.Each(o => openssl.StandardInput.WriteLine(o));
}
}
至此,支付宝条码支付功能就已经介绍完了,其他支付宝支付的调用也是类似的。