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

版权声明:本文为starfd原创文章,转载请标明出处。 https://blog.csdn.net/starfd/article/details/83585230

首先先附上微信电子发票报销方接口列表的官方链接,如果你是.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、SDK中微信Token的坑
因为InvoiceApi中的静态方法第一个参数accessTokenOrAppId,在上面的示例中就简单的使用了appId来作为方法参数,但实际它底层是通过AccessTokenContainer来获取Token的,所以这里就是第一个坑,其默认是从缓存中读取Token,但微信的Token,说实在的,老是莫名其妙就Token过期或者失效了,所以建议还是老老实实的自己获取Token,并且是强制每次要用时都重新生成Token

string appId="";
string appSecret="";
var token = AccessTokenContainer.TryGetAccessToken(appId, appSecret, true);
var inv = InvoiceApi.GetInvoiceInfo(token,card_id,encrypt_code);

2、微信报销方批量获取发票列表的坑
你可以通过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);//通过移除已经匹配到请求参数的来保证不会重复匹配
	}
}

3、发票状态更新的坑
因为按正常的流程,当你从微信卡包成功获取发票信息、并持久化在你本地进入报销流程时,你需要通过微信的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再获取一次发票信息,判断下发票目前状态实际为何种状态,如果发票状态已经为你想要更改的状态,那么就可以继续执行后续的业务逻辑。

猜你喜欢

转载自blog.csdn.net/starfd/article/details/83585230
今日推荐