咱們是一個位於三線城市的購物中心,雖然已經開業多年,可是受益於良好的招商和平常運營,客流量在同城同類型項目中一直比較穩定。在節假日出場車流高峯期的時候,因爲人工收費的效率問題,會致使車輛積壓在收費口等待繳費。我曾在停車場出口掐表測算過,人工收費平均須要20-30秒才能出一輛車。這個問題嚴重影響到了駕車客戶的體驗,所以咱們在官微上提供了停車場在線繳費功能,讓提早線上繳費的用戶到達停車場出口的時候無須等待直接離開,將一輛車經過出口閘機的時間下降到了平均2-3秒,通行效率大幅提高。前端
在線繳費功能前期是以H5實現的,17年移植到了小程序版。上線首月在線提早繳費的用戶比例就達到了20%左右,通過一段時間運行,這個比例穩定在70%以上,完全解決了停車場出口擁堵的問題。 python
因爲官微上只能支持微信支付(好像是廢話),爲了支持部分支付寶繳費用戶,也爲了補全繳費途徑,公司計劃在停車場電梯廳內部署幾臺繳費機。繳費機採用了落地式觸摸屏,因爲採用的c/s架構,前端就是一個簡單的UI呈現,所以對性能幾乎沒有要求。git
在設計繳費機系統的過程當中,涉及到須要同時支持微信支付和支付寶支付,基本的業務邏輯就是用戶提交車牌號到後臺,後臺查詢到費用後用微信支付寶sdk生成二維碼支付參數,後臺再把參數反饋給繳費機,等待用戶經過微信或支付寶客戶端掃描二維碼付款。 express
在最初的第一個版本中,爲了同時支持微信和支付寶,咱們在繳費機主界面上放置了兩個二維碼,提示用戶用對應的app掃描支付,這兩個二維碼分別使用微信的Native支付和支付寶的當面付產品。很顯然這個體驗並不會很好,因而準備經過一個二維碼同時支持微信和支付寶。小程序
調用微信python sdk獲取Native支付urlapi
wxpay = WXPay(app_id=WXAPPID, mch_id=WXMCHID, key=WXKEY, cert_pem_path=None, key_pem_path=None, timeout=6000, use_sandbox=False) wxresp = wxpay.unifiedorder(dict(body='三盛國際廣場-停車繳費-%s' % plateno, out_trade_no='%s' % (orderNo,), product_id=plateno, total_fee=payable, time_start=datetime.datetime.now().strftime("%Y%m%d%H%M%S"), time_expire=(datetime.datetime.now() + datetime.timedelta(minutes=5)).strftime("%Y%m%d%H%M%S"), notify_url='https://apiserver/wxnotify', trade_type='NATIVE')) if wxresp['return_code'].upper() == 'SUCCESS' and wxresp['result_code'].upper() == 'SUCCESS' and wxresp['appid'] == WXAPPID: wxurl = wxresp['code_url']
wxurl是相似下面這樣的格式: weixin://wxpay/bizpayurl?sign=XX&appid=XX&mch_id=XX&product_id=XX&time_stamp=XX&nonce_str=XX
瀏覽器
調用支付寶python sdk獲取當面付url安全
alipay_client_config = AlipayClientConfig() alipay_client_config.server_url = 'https://openapi.alipay.com/gateway.do' alipay_client_config.app_id = ALI_APPID alipay_client_config.app_private_key = ALI_PRI_KEY alipay_client_config.alipay_public_key = ALI_PUB_KEY aliclient = DefaultAlipayClient(alipay_client_config=alipay_client_config, logger=logger) alimodel = AlipayTradePrecreateModel() alimodel.out_trade_no = orderNo alimodel.total_amount = payable / 100 alimodel.subject = "三盛國際廣場-停車費-%s" % plateno alimodel.qr_code_timeout_express = "5m" alirequest = AlipayTradePrecreateRequest(biz_model=alimodel) udf_params = dict() udf_params[P_NOTIFY_URL] = "https://apiserver/alinotify" alirequest.udf_params = udf_params aliresponse = aliclient.execute(alirequest) if aliresponse: response = AlipayTradePrecreateResponse() response.parse_response_content(aliresponse) if response.is_success(): aliurl = response.qr_code
aliurl是相似下面這樣的格式:服務器
https://qr.alipay.com/bavh4wjlxf12tper3a
在第一個版本中,繳費機顯示的二維碼分別是微信和支付寶服務器返回給咱們的參數編碼而成的,既然須要一碼支付,顯然不能直接拿來用,畢竟這兩個巨頭都不支持自家APP掃對方的二維碼。微信
因而咱們想到的是經過一個咱們本身生成的二維碼做爲橋樑,當獲取到微信和支付寶返回的支付參數後,先臨時保存下來,而後製做一個帶參數的H5頁面傳送給繳費機生成二維碼給用戶掃碼,當app掃碼解析出頁面地址訪問的時候,服務器根據瀏覽器agent信息跳轉對應的支付url給app便可。
if 'MicroMessenger' in agent: #生成微信Native支付url return redirect(wxurl) elif 'Alipay' in agent: #生成支付寶當面付支付url return redirect(aliurl) else: return '請打開微信或支付寶掃描付款二維碼!'
這個邏輯看起來好像沒問題,很完美的解決了用戶體驗上的問題。實際上裏面還有一個坑,就是支付寶當面付這樣操做沒任何問題,而微信支付不容許這樣操做,微信會判斷支付二維碼是經過攝像頭掃描直接獲取仍是瀏覽器跳轉過來的,當判斷非瀏覽器直接掃碼會拒絕支付,微信支付這樣作的緣由可能避免安全問題。
既然微信的Native支付不能直接用,我只能曲線救國了,由於咱們前期已經有過一個H5繳停車費的版本,所以此次直接拿來從新改造了一下,當判斷爲微信掃碼的時候,調用微信的JSAPI支付,在H5頁面內完成支付。
if 'MicroMessenger' in agent: #生成微信h5支付url return redirect(wxh5url) elif 'Alipay' in agent: #生成支付寶當面付支付url return redirect(aliurl) else: return '請打開微信或支付寶掃描付款二維碼!'
較之支付寶的當面付來講,須要多作一個H5支付頁面,爲了讓體驗和原生支付一致,咱們的H5頁面參照了官方支付風格。
這樣一套流程跑下來,基本把微信和支付寶公用一個二維碼支付的問題解決了,後面若是計劃支持QQ支付、百度錢包、京東支付之類也能夠依葫蘆畫瓢。