View Source ExWechatpay (ex_wechatpay v0.1.5)
微信支付/WechatPay SDK in Elixir
该SDK提供了一种简单的方式来与微信支付API进行交互。它包括了部分微信支付API,包括付款、退款、查询订单等。
安装
将SDK添加到你的mix.exs文件中:
def deps do
[
{:ex_wechatpay, "~> 0.1"}
]
end
运行mix deps.get来安装SDK。
Usage
在使用该SDK之前,应当提前准备好如下配置:
- appid: 第三方用户唯一凭证;
- mchid: 商户号;
- notify_url: 订单信息的回调地址;
- apiv3_key: apiv3密钥
- wx_pubs: 微信平台证书列表,如果是首次使用可不配置,用
ExWechatpay.get_certificates/2
可下载证书信息 - client_serial_no: 商户API证书序列号,如果是首次使用可不配置,用
ExWechatpay.get_certificates/2
可下载证书信息 - client_key: 商户API证书私钥
- client_cert: 商户API证书
- http_module: HTTP客户端模块(实现了ExWechatpay.Http behaviour),默认使用ExWechatpay.Http.Finch
- http_client: HTTP客户端实例,如果http_module为ExWechatpay.Http.Finch, http_client为ExWechatpay.Http.Finch.new()
假设配置如下:
// test_data
{
"appid": "wxefd6b2150cac",
"mchid": "1611167",
"notify_url": "https://www.example.com",
"apiv3_key": "A21AjklasMDKNmA1232D91281230",
"client_serial_no": "1C984734F30327FD63C46DA5386C086104",
"client_key": "-----BEGIN PRIVATE KEY-----.....-----END PRIVATE KEY-----\n",
"client_cert": "-----BEGIN CERTIFICATE-----.....-----END CERTIFICATE-----\n",
"wx_pubs": [
{
"wechatpay-serial": "35CE31ED8F4A5037C51B5ADA03265E72",
"public_key": "-----BEGIN PUBLIC KEY-----.....-----END PUBLIC KEY-----\n"
}
]
}
使用客户端前,先初始化一个client实例:
iex> test_data = File.read!("test.json") |> Jason.decode!()
iex> client =
ExWechatpay.Client.new(
appid: test_data["appid"],
mchid: test_data["mchid"],
notify_url: test_data["notify_url"],
apiv3_key: test_data["apiv3_key"],
client_serial_no: test_data["client_serial_no"],
client_key: test_data["client_key"],
client_cert: test_data["client_cert"],
wx_pubs:
test_data["wx_pubs"] |> Enum.map(fn x -> {x["wechatpay-serial"], x["public_key"]} end)
)
再启动SDK实例即可使用:
iex> wechat = ExWechatpay.new(client: client)
iex> ExWechatpay.start_link(wechat: wechat)
iex> ExWechatpay.get_certificates(wechat, verify: false) # 首次获取微信平台证书列表时可设置不验证
{
:ok,
%{
"data" => [
%{
"certificate" => "-----BEGIN CERTIFICATE-----\nMIID3DCCAsSgAwIBAgIUNc4x7Y9KULkw...\n-----END CERTIFICATE-----",
"effective_time" => "2021-06-23T14:09:22+08:00",
"encrypt_certificate" => %{
"algorithm" => "AEAD_AES_256_GCM",
"associated_data" => "certificate",
"ciphertext" => "BoiqBLxeEtXMAmD7pm+...w==",
"nonce" => "2862867afb33"
},
"expire_time" => "2026-06-22T14:09:22+08:00",
"serial_no" => "35CE31ED8F4A50B930FF8D37C51B5ADA03265E72"
}
]
}
}
功能列表:
- [x] get_certificates: 获取微信平台证书列表
- [x] verify: 验证微信回调签名
- [x] create_native_transaction: Native下单API
- [x] create_jsapi_transaction: JSAPI下单API
- [x] create_h5_transaction: H5下单API
- [x] query_transaction: 查询订单API
- [x] close_transaction: 关闭订单API
- [x] miniapp_payform: 小程序生成支付表单
- [x] create_refund: 申请退款API
许可证
该SDK基于MIT许可证发布。有关更多信息,请参见LICENSE文件。
联系方式
如果你有任何问题或反馈,请发送电子邮件至tt67wq@outlook.com或者发起issue。
Summary
Functions
生成小程序支付表单 create a miniapp payform with a jsapi transaction_id
create a new instance of this WechatPayment module
Types
@type err_t() :: {:error, ExWechatpay.Error.t()}
@type ok_t(ret) :: {:ok, ret}
@type t() :: %ExWechatpay{ client: ExWechatpay.Client.t(), json_module: atom(), name: atom() }
Functions
关闭订单API https://pay.weixin.qq.com/wiki/doc/apiv3/apis/chapter3_4_3.shtml
Examples
:ok = close_transaction(wechat, "1217752501201407033233368018")
@spec create_h5_transaction(t(), ExWechatpay.Typespecs.string_dict()) :: ok_t(ExWechatpay.Typespecs.string_dict()) | err_t()
H5下单API https://pay.weixin.qq.com/wiki/doc/apiv3/apis/chapter3_3_1.shtml
Examples
{:ok, %{"ht_url" => "https://wx.tenpay.com/cgi-bin/..........."}} = create_h5_transaction(wechat, %{
"description" => "Image形象店-深圳腾大-QQ公仔",
"out_trade_no" => "1217752501201407033233368018",
"notify_url" => "https://www.weixin.qq.com/wxpay/pay.php",
"amount" => %{
"total" => 1,
"currency" => "CNY"
},
"scene_info" => %{
"payer_client_ip" => "some ipaddr"
}
})
@spec create_jsapi_transaction(t(), ExWechatpay.Typespecs.string_dict()) :: ok_t(ExWechatpay.Typespecs.string_dict()) | err_t()
JSAPI下单 https://pay.weixin.qq.com/wiki/doc/apiv3/apis/chapter3_1_1.shtml
Examples
{:ok, %{"prepay_id" => "wx03173911674781a20cf50feafc02ff0000"}} = create_jsapi_transaction(wechat, %{
"description" => "Image形象店-深圳腾大-QQ公仔",
"out_trade_no" => "1217752501201407033233368018",
"notify_url" => "https://www.weixin.qq.com/wxpay/pay.php",
"amount" => %{
"total" => 1,
"currency" => "CNY"
},
"payer" => %{
"openid" => "oUpF8uMuAJO_M2pxb1Q9zNjWeS6o"
}
})
@spec create_native_transaction(t(), ExWechatpay.Typespecs.string_dict()) :: ok_t(ExWechatpay.Typespecs.string_dict()) | err_t()
Native下单API https://pay.weixin.qq.com/wiki/doc/apiv3/apis/chapter3_4_1.shtml
Examples
{:ok, %{"code_url" => "weixin://wxpay/bizpayurl?pr=CvbR9Rmzz"}} =
ExWechatpay.Wechat.Client.Finch.create_native_transaction(wechat, %{
"description" => "Image形象店-深圳腾大-QQ公仔",
"out_trade_no" => "1217752501201407033233368018",
"notify_url" => "https://www.weixin.qq.com/wxpay/pay.php",
"amount" => %{
"total" => 1,
"currency" => "CNY"
}
})
@spec create_refund(t(), ExWechatpay.Typespecs.string_dict()) :: ok_t(ExWechatpay.Typespecs.string_dict()) | err_t()
申请退款API https://pay.weixin.qq.com/wiki/doc/apiv3/apis/chapter3_3_9.shtml
Examples
{:ok, %{
"amount" => %{
"currency" => "CNY",
"discount_refund" => 0,
"from" => [],
"payer_refund" => 1,
"payer_total" => 1,
"refund" => 1,
"refund_fee" => 0,
"settlement_refund" => 1,
"settlement_total" => 1,
"total" => 1
},
"channel" => "ORIGINAL",
"create_time" => "2023-06-05T11:44:56+08:00",
"funds_account" => "AVAILABLE",
"out_refund_no" => "refund_E6QEe56ERo",
"out_trade_no" => "test_QQuuheTjp7",
"promotion_detail" => [],
"refund_id" => "50302305912023060535313670012",
"status" => "PROCESSING",
"transaction_id" => "4200001869202306052617880791",
"user_received_account" => "支付用户零钱"
}} = ExWechatpay.Wechat.Client.Finch.create_refund(wechat, %{
"amount" => %{"refund" => 1},
"out_refund_no" => "refund_E6QEe56ERo",
"out_trade_no" => "test_QQuuheTjp7"
})
解密回调信息
Examples
{:ok, "1217752501201407033233368018"} = decrypt(wechat, %{
"algorithm" => "AEAD_AES_256_GCM",
"ciphertext" => "BoiqBLxeEtXMAmD7pm+...w==",
"nonce" => "2862867afb33",
"associated_data" => "transaction"
})
获取平台证书 https://pay.weixin.qq.com/wiki/doc/apiv3/apis/wechatpay5_1.shtml
后续用 openssl x509 -in some_cert.pem -pubkey 导出平台公钥
Examples
{
:ok,
%{
"data" => [
%{
"certificate" => "-----BEGIN CERTIFICATE-----
MIID3DCCAsSgAwIBAgIUNc4x7Y9KULkw... -----END CERTIFICATE-----",
"effective_time" => "2021-06-23T14:09:22+08:00",
"encrypt_certificate" => %{
"algorithm" => "AEAD_AES_256_GCM",
"associated_data" => "certificate",
"ciphertext" => "BoiqBLxeEtXMAmD7pm+...w==",
"nonce" => "2862867afb33"
},
"expire_time" => "2026-06-22T14:09:22+08:00",
"serial_no" => "35CE31ED8F4A50B930FF8D37C51B5ADA03265E72"
}
]
}
} = get_certificates(wechat)
@spec miniapp_payform(t(), String.t()) :: ok_t(ExWechatpay.Typespecs.string_dict())
生成小程序支付表单 create a miniapp payform with a jsapi transaction_id
Examples
{:ok, %{
"appid" => "wxefd6b215fca0cacd",
"nonceStr" => "vFPjBwiBRDaf",
"package" => "prepay_id=testO_1234567890",
"paySign" => "nxairksHJ3UCp8iHU+F47IIBrV/lmmTjE5rQfOAChtgrtdEo6NX0uhpRfsDEb8eSa7z0c861KWu93fZxOycM8JcQcXEek6e1EMjntDgz3M3+8WhGHm+lxDD7khy9vy9A4iOERxCccXPs0Auep0/a1V5pDHRvrU+5QN0c483mvbS6GwiUUKMwyi78iCap8hezd7ya+YWdChqsbRmz/LpgVf0mmfvzWppAxRCKtCKOU0NNluiKMqdmx9fLwWLEnnJA6wLXvG3zs4EIB/06ibM3OQmcI4nNnFW40jBtuH7yVkH3i+ZhSv0GnUxaLy34Br4cwPpY4FzAuSfOHtC3Nx5/pA==",
"signType" => "RSA",
"timeStamp" => 1685676354
}} = ExWechatpay.Wechat.Client.Finch.miniapp_payform(wechat, "testO_1234567890")
create a new instance of this WechatPayment module
Options
:name
(atom/0
) - name of this process The default value isExWechatpay
.:client
(term/0
) - Required. client instance ofExWechatpay.Client
:json_module
(atom/0
) - json module The default value isJason
.
@spec query_transaction(t(), :out_trade_no | :transaction_id, String.t()) :: ok_t(ExWechatpay.Typespecs.string_dict()) | err_t()
查询订单API https://pay.weixin.qq.com/wiki/doc/apiv3/apis/chapter3_4_2.shtml
Examples
{:ok,
%{
"amount" => %{
"currency" => "CNY",
"payer_currency" => "CNY",
"payer_total" => 1,
"total" => 1
},
"appid" => "wxefd6b215fca0cacd",
"attach" => "",
"bank_type" => "OTHERS",
"mchid" => "1611120167",
"out_trade_no" => "testO_1234567890",
"payer" => %{"openid" => "ohNY75Jw8MlsKuu4cFBbjmK4ZP_w"},
"promotion_detail" => [],
"success_time" => "2023-05-31T11:14:40+08:00",
"trade_state" => "SUCCESS",
"trade_state_desc" => "支付成功",
"trade_type" => "NATIVE",
"transaction_id" => "4200001851202305317391703081"
}} = ExWechatpay.Wechat.Client.Finch.query_transaction(wechat, :out_trade_no, "1217752501201407033233368018")
@spec verify(t(), ExWechatpay.Typespecs.headers(), ExWechatpay.Typespecs.body()) :: boolean()
回执、回调验签 https://pay.weixin.qq.com/wiki/doc/apiv3/wechatpay/wechatpay4_1.shtml
Examples
true = verify(wechat, [{"Wechatpay-Serial" => "35CE31ED8F4A50B930FF8D37C51B5ADA03265E72"}], "body")