【微信卡包发票导入】微信电子发票报销方服务端接入时遇到的那些坑

首先先附上微信电子发票报销方接口列表的官方链接,如果你是.NET开发,那么你可以通过Senparc.Weixin.MP来快速开发相应的微信电子发票功能,该功能在其16.4.0版本开始提供,16.4.9版本修复报销方的bug(修复PR代码由本人提供),16.4.10电子发票原作者又做了一些调整,重新定义了发票实体,所以电子发票部分16.4.916.4.10不兼容,然后目前16.4.10报销方部分已在实际生产环境进行过测试,目前尚未发现报销方相关的功能存在bug,商户和开票平台部分因为没实际业务需求,所以无法进行测试。

略去前端部分的内容,对于电子发票报销方,微信提供了以下两类API:

  • 查询发票
  • 更新状态

然后每类API都默认提供单个以及批量两种操作,所以总共是4个API接口。

Senparc.Weixin.MP中,电子发票相关代码均在Senparc.Weixin.MP.AdvancedAPIs.InvoiceApi静态类下,每个静态方法对应一个API接口,所有的方法均采用了同种代码方式,接下来就要说到开发中遇到的坑了,当然有些是SDK的坑,有些是微信API自身的坑。

先简单的列下接入示例代码

string appId="";
string appSecret="";
//接下来只需要简单的通过调用InvoiceApi.XXX方法就可以来完成调用某个API
//以获取指定单张电子发票为例
string card_id;//发票卡券的 card_id
string encrypt_code;//发票卡券的加密 code ,和 card_id 共同构成一张发票卡券的唯一标识
var inv = InvoiceApi.GetInvoiceInfo(appId,card_id,encrypt_code);
//当然每个API方法都有对应的异步方法,比如GetInvoiceInfoAsync

总的来说,接入还是相当简单的,所以接下来就要讲第一个坑了

1、微信报销方批量获取发票列表的坑
你可以通过InvoiceApi.GetInvoiceListInfo来批量获取发票列表,此时微信会返回你所请求的所有card_idencrypt_code所对应的发票信息,因为发票的报销涉及状态变更,所以card_idencrypt_code我们是需要在本地持久化存储的,那么我们也就需要将请求的card_idencrypt_code与返回的发票进行一一对应,然后关键点来了,返回的集合信息中,每张发票只有card_id,没有encrypt_code,如果你没注意到微信文档上描述的发票卡券的加密 code ,和 card_id 共同构成一张发票卡券的唯一标识,直接按card_id去与请求的card_id做对应的话,那么就有可能会导致错误,所以接下来就是关键点:微信返回的列表与请求参数是一一对应的,所以可以简单的按索引来匹配,但我没测试假如请求的数据中有一条是错误的,返回的结果会怎么样,有兴趣的可以试验下

List<InvoiceItem> itemList;
var invList = InvoiceApi.GetInvoiceListInfo(token, itemList);
if (invList.errcode == 0)
{
	for(var i=0;i<invList.item_list.Count;i++)
	{
		//两者一一对应
		var item = itemList[i];
		var inv = invList.item_list[i];
		//当然如果你不放心这种写法,那么可以采用下一种
		var currentItem = itemList.First(m => m.card_id == inv.card_id);
		itemList.Remove(currentItem);//通过移除已经匹配到请求参数的来保证不会重复匹配
	}
}

2、发票状态更新的坑
因为按正常的流程,当你从微信卡包成功获取发票信息、并持久化在你本地进入报销流程时,你需要通过微信的API来更新发票状态为INVOICE_REIMBURSE_LOCK发票已锁定;相应的假如你在本地删除了该发票,你也需要告知微信目前该发票状态要更改为INVOICE_REIMBURSE_INIT发票初始状态,未锁定;如果报销完成了,则你需要更新状态INVOICE_REIMBURSE_CLOSURE发票已核销。而此处的坑就在于如果发票在微信那里状态本身为INVOICE_REIMBURSE_INIT,你再通过InvoiceApi.UpdateInvoiceStatus去更新发票为INVOICE_REIMBURSE_INIT状态时,即更新为同种状态,微信会返回更新失败……当然这也不能说微信错了,只能说这块响应不友好,但我们业务中为了保证发票能够解锁,如果解锁失败就不允许本地删除发票(因为在微信卡包中,锁定状态的发票是不能删除的,也无法再次被选择,所以假如你本地删除了card_id和encrypt_code,那么那几张灰色的发票信息就要在你的卡包里一辈子了,因为你再也没有正常途径可以取到card_id和encrypt_code!!!),所以此处如果你更新发票状态失败了,你可以再通过InvoiceApi.GetInvoiceInfo再获取一次发票信息,判断下发票目前状态实际为何种状态,如果发票状态已经为你想要更改的状态,那么就可以继续执行后续的业务逻辑。

3、微信公众号Token
因为微信公众号AccessToken有时间限制,所以为了贪图方便,我们可能会直接每次都通过AccessTokenContainer.TryGetAccessToken(appId,appSecret,true)强制刷新AccessToken,测试期间可能会发现一切正常,但AccessToken其实每天都有刷新次数上限(2000),所以如果上了生产环境还每次都强制刷新AccessToken的话,可能很快就会达到每日上限!!!另外如果你们有多个环境(假设A/B两个环境),而每个环境都用了同样的appId,那么恭喜你,只要你在A访问了一次微信相关的功能获取了一个AccessToken,然后在B又操作了一次微信相关的功能又获取了一个新的AccessToken,那么5分钟之后A的AccessToken就过期,而且因为expire_in还没到,框架也不会帮你自动刷新Token,然后A环境所有与微信相关的功能都game over……

4、Ip白名单
微信公众号在设置时需要配置Ip白名单,只有白名单内指定的Ip微信才会允许在Jsapi中访问相关功能,所以如果你的服务器是通过代理服务器上网,那么就很可能存在对外Ip地址发生变化的问题,而且最坑的是:Ip地址不在白名单时,提示是签名错误

评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值