咱们是一个位于三线城市的购物中心,虽然已经开业多年,可是受益于良好的招商和平常运营,客流量在同城同类型项目中一直比较稳定。在节假日出场车流高峰期的时候,因为人工收费的效率问题,会致使车辆积压在收费口等待缴费。我曾在停车场出口掐表测算过,人工收费平均须要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支付、百度钱包、京东支付之类也能够依葫芦画瓢。