目录
# 1. 开发准备
在开始开发前,请确认已提前做好以下准备工作:
(1)拥有微信服务号,并且已完成认证;
(2)拥有可以联网的打印机;
(3)拥有云端后台,可以对打印机发出指令。
# 2. 时序图
# 3. 拉起发票列表(微信内)
# 3.1 接口说明
该接口功能为在微信内拉起发票卡券列表(如下图所示),用户勾选需要提交打印的发票后,开发者获得所选发票的标识信息。
本接口的调用须遵循JS-SDK的调用方法,请在开发前阅读JS-SDK说明文档以熟悉开发术语和基本接口的调用。
# 3.2 请求方式
参考示例代码,传入下表中的参数即可成功拉起发票列表页。
参数 | 类型 | 是否必填 | 描述 |
---|---|---|---|
timestamp | string(32) | 是 | 签名生成的时间戳,采用unix十位时间戳 |
nonceStr | string(32) | 是 | 用于生成签名的随机字符串,签名生成方法, 参见 6.3 |
signType | string(32) | 是 | 签名类型,签名生成方法见 参见6.3 |
cardSign | string(64) | 是 | 发票签名,按照文档 生成完签名后作为参数传入, 参见6.3 |
# 3.3 返回结果
用户点击确认或取消后,将按下表所列字段格式及含义返回结果。
返回字段 | 类型 | 值 | 含义 |
---|---|---|---|
err_msg choose_invoice | string | ok | 选取发票成功 |
fail | 选取发票失败 | ||
cancel | 选取发票取消 | ||
choose_invoice_info | object | 对象列表 | 用户选中的发票列表 |
choose_invoice_info的对象结构如下
{ card_id = @"", encrypt_code = @"" app_id=@"" }
各字段含义如下:
字段 | 类型 | 描述 |
---|---|---|
card_id | string | 所选发票卡券的card_id |
encrypt_code | string | 所选发票卡券的加密code,打印服务商可以通过card_id和encrypt_code获得用户申请打印的发票信息及PDF文档 |
app_id | string | 开票方的appid |
获得card_id和encrypt_code后,开发者可以按照 查询发票信息并获取PDF文档 一节的方法,获取每张发票的结构化信息及PDF文件。
# 3.4 示例代码
wx.config({
beta: true,
debug: false,
appId: "wx00000000000000",
timestamp: 1489030247,
nonceStr: "(9J4YRV[#@",
signature: "f027317f8910000000000000000000",
jsApiList: ['chooseInvoice']
});
wx.ready(function () {
wx.invoke('chooseInvoice', {
'timestamp': 1489030247, // 卡券签名时间戳
'nonceStr': "p(6N&7WOAF", // 卡券签名随机串
'signType': 'SHA1', // 签名方式,默认'SHA1'
'cardSign': "a72043eed36c74300000000000000000" // 卡券签名
}, function(res) {
alert(JSON.stringify(res));
}
});
});
# 4. 拉起发票列表(外部App)
# 4.1 接口说明
微信也支持外部App拉起发票列表的接口。与微信内拉起发票列表接口相似,在用户勾选并点击确认后,可以获得发票的标识数据。
该接口须遵循JS-SDK的调用方法,并且必须满足一定条件才能调用。请在开发前检查自己是否已满足以下条件:
1 )获得一个已认证的微信开放平台账号;
2 )在微信开放平台上创建一个应用并提交应用通过审核。未注册应用的开发者可在开发者应用登记页面进行登记;
3 )已下载微信电子发票报销SDK,iOS及Android下载地址见电子发票文档资源下载部分;
4 )通读 微信开放平台资源中心中关于SDK使用的基本方法,并正确导入到自身的应用中。
# 4.2 请求方式
iOS 应用
参考压缩包内的OpenSDK1.7.7文件,使用时调用WXChooseInvoice类。其中需要签名的部分,参考JS-SDK的调用方式。
Android 应用
参考压缩包内,进入jar文件,使用时调用WXChooseCard类,并传入CardType为“INVOICE”。其中需要签名的部分,参考JS-SDK的调用方式。
# 4.3 返回结果
返回结果请与微信内拉起发票列表的返回结果相同,参见3.3。
# 5 查询发票信息并获取PDF文档
# 5.1 接口说明
报销方在上一步获得用户选择提交的电子发票标识参数后,可以通过该接口查询电子发票的结构化信息,并获取发票PDF文件。
# 5.2 请求方式
请求URL:https://api.weixin.qq.com/card/invoice/reimburse/getinvoiceinfo?access_token={access_token}
请求方法:POST
请求参数:
请求参数使用JSON格式,参数清单如下
参数 | 类型 | 是否必填 | 描述 |
---|---|---|---|
card_id | string | 是 | 发票卡券的card_id |
encrypt_code | string | 是 | 发票卡券的加密code,和card_id共同构成一张发票卡券的唯一标识 |
# 5.3 返回结果
数据格式:JSON
参数 | 类型 | 是否必填 | 描述 |
---|---|---|---|
errcode | Int | 是 | 错误码 |
errmsg | String | 是 | 错误信息 |
当错误码为0时,有以下信息:
参数 | 类型 | 是否必填 | 描述 |
---|---|---|---|
card_id | String | 是 | 发票id |
begin_time | Int | 是 | 发票的有效期起始时间 |
end_time | Int | 是 | 发票的有效期截止时间 |
openid | String | 是 | 用户标识 |
type | String | 是 | 发票的类型,如广东增值税普通发票 |
payee | String | 是 | 发票的收款方 |
detail | String | 是 | 发票详情 |
user_info | Object | 是 | 用户可在发票票面看到的主要信息 |
user_info包含以下信息:
参数 | 类型 | 是否必填 | 描述 |
---|---|---|---|
fee | Int | 是 | 发票加税合计金额,以分为单位 |
title | String | 是 | 发票的抬头 |
billing_time | Int | 是 | 开票时间,为十位时间戳(utc+8) |
billing_no | String | 是 | 发票代码 |
billing_code | String | 是 | 发票号码 |
info | List | 否 | 商品信息结构,见下方说明 |
fee_without_tax | Int | 是 | 不含税金额,以分为单位 |
tax | Int | 是 | 税额,以分为单位 |
pdf_url | String | 是 | 这张发票对应的PDF_URL |
trip_pdf_url | String | 是 | 其它消费凭证附件对应的URL,如行程单、水单等 |
reimburse_status | String | 是 | 发票报销状态,见 备注6.2 |
check_code | String | 是 | 校验码(必填) |
buyer_number | String | 否 | 购买方纳税人识别号(选填) |
buyer_address_and_phone | String | 否 | 购买方地址、电话(选填) |
buyer_bank_account | String | 否 | 购买方开户行及账号(选填) |
seller_number | String | 否 | 销售方纳税人识别号(选填) |
seller_address_and_phone | String | 否 | 销售方地址、电话(选填) |
seller_bank_account | String | 否 | 销售方开户行及账号(选填) |
remarks | String | 否 | 备注 |
cashier | String | 否 | 收款人,发票左下角处(选填) |
maker | String | 否 | 开票人,发票有下角处(选填) |
info为发票项目明细信息。数据格式表现为Object列表,每个Object包含以下信息:
参数 | 类型 | 是否必填 | 描述 |
---|---|---|---|
name | String | 是 | 项目(商品)名称 |
num | Int | 是 | 项目数量 |
unit | String | 是 | 项目单位 |
price | Int | 是 | 单价,以分为单位 |
# 6 备注
# 6.1 错误码
在微信电子发票报销方案中,涉及的错误码及错误码含义如下:
错误码 | 含义 |
---|---|
0 | 成功 |
72015 | 没有操作发票的权限 |
72017 | 发票抬头不一致 |
72023 | 发票已被其他公众号锁定 |
72024 | 发票状态错误 |
# 6.2 发票状态
通过接口获取发票信息时,涉及的发票状态码及状态含义如下:
状态 | 含义 |
---|---|
INVOICE_REIMBURSE_INIT | 发票初始状态,未锁定,可提交报销 |
INVOICE_REIMBURSE_LOCK | 发票已锁定,无法重复提交报销 |
INVOICE_REIMBURSE_CLOSURE | 发票已核销,从用户卡包中移除 |
# 6.3 获取api_ticket
<span id = "21>
# 6.3.1 请求方式
请求URL:https://api.weixin.qq.com/cgi-bin/ticket/getticket?access_token=ACCESS_TOKEN&type=wx_card
请求方法:GET
# 6.3.2 返回结果
返回格式:JSON
参数 | 类型 | 是否必填 | 描述 |
---|---|---|---|
errcode | Int | 是 | 错误码 |
errmsg | String | 是 | 错误信息 |
ticket | String | 是 | 发票签名临时票据,即为后续发票签名中需要使用的Api_ticket |
expires_in | Int | 是 | 有效期,以秒为单位。在有效期内重复请求ticket不会被刷新 |
# 6.3.3 示例代码
返回:
{
"errcode":0,
"errmsg":"ok",
"ticket":"bxLdikRXVbTPdHSM05e5u5sUoXNKdvsdshFKA",
"expires_in":7200
}
# 6.4 发票签名方法
在应用JS-SDK和App SDK时需要进行签名,以便校验数据传输过程未被篡改,签名实现方法如下:
参与签名参数
参数 | 描述 |
---|---|
cardType | 填入INVOICE |
timestamp | 拉起发票列表时使用的时间戳(utc+8) |
appid | 调用该接口的appid |
nonceStr | 随机字符串 |
api_ticket | 通过acess_token换取的临时票据,详情 参见6.3 |
签名方法
将 api_ticket、appid、timestamp、nonceStr、cardType的value值进行字符串的字典序排序。再将所有参数字符串拼接成一个字符串进行sha1加密,得到cardSign。
例如:api_ticket=aaa、appid=aab、timestamp=abc、nonceStr=bbc、cardType=cde,那么先拼成字符串aaaaababcbbccde,再将此字符串进行sha1加密,得到cardSign。