【微信卡包發票導入】微信電子發票報銷方服務端接入時遇到的那些坑

首先先附上微信電子發票報銷方接口列表的官方鏈接,如果你是.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地址不在白名單時,提示是簽名錯誤

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章