openerp支付寶當面支付(掃條碼)

 openerp要集成支付寶支付,我們項目一般都面對例如咖啡廳、農貿市場、超市等等收銀臺使用的屏幕上面,一般使用的屏幕都是安卓系統。這裏我們只考慮我們的erp的建立,當然一個這樣的項目包括很多,我們這裏只是涉及到支付寶支付方面,並且由於只是使用到掃描槍的情況,符合這種場景的支付方式就是支付寶的face2face當面付的方式。

        支付的當面付在開始之前,必須要以商家的方式申請在支付寶的開放平臺的的當面付的簽證,具體查看支付寶的開放平臺的介紹(誰叫你使用人家的東西,一切按照官網的內容爲準)。這個時候你就會收到支付寶的當面付的appid,支付寶的私鑰、公鑰,這些都是要用上在開發過程中,這裏不得不吐槽一下支付寶,比起微信支付,傳輸的參數要多很多,並且安全級別要高,當面付現在只是支持RSA簽名編碼跟解碼,後面會說到底怎麼個麻煩法。

   在開始之前我們要先準備一下相關內容跟參數:

   1.商家的appid,具體怎麼查看,查詢支付寶官網,不行就找客服(支付寶的客服還是不錯的)

   2.用openssel生產自己(開發者的)私鑰以及公鑰,具體還是看官網,裏面有詳細的介紹

   3.上傳你生產的公鑰到支付寶用於解碼我們生產的sign簽名,並且複製支付寶的公鑰到本地用於解碼支付寶返回來的sign簽名

   開發流程:

    1.新建一個openerp模塊:payment_alipay(具體不同版本可能有些不相同,我用的openerp7)

    wKiom1cot06RBPwiAAAoNWq0OuE270.png

   2.主要處理代碼:

     wKiom1cot1mDMd9VAAA5YUPK0yQ047.png

   3.開發本質上面就是開發一個RESTful過程,就是訪問url+參數,我程序接收到post過來的數據然後進行處理

   相關代碼內容:

mail.py(主要是做route過程)

@http.route('/payment/alipay/scancode', type='json', auth='none', methods=['POST'])
def alipay_scancode(self, **post):
    logger.info('Beginning Alipay notify with post data %s', pprint.pformat(post))  # debug
return_pay_msg = {'return_code': 'FAIL', 'return_msg': ''}
    cr, uid, context = request.cr, SUPERUSER_ID, request.context
try:
        money = float(post['money'])
except ValueError:
        return_pay_msg['return_msg'] = u'傳輸的金錢格式有問,只能爲數字!'
return return_pay_msg

if post['orderID'] and isinstance(money, float) and post['auth_code'] and post['subject']:
        pay_record = request.registry['payment.record']  # 註冊addons裏面的payment_record.models.payment_record.py
        # 裏面的class PaymentRecord
record = dict()
        record['ref_id'] = str(post['orderID'])
        record['type'] = u'支付寶'
record['sub_type'] = u'支付寶掃條形碼支付'
record['fee'] = str(post['money'])
        record['subject'] = post['subject']
        record_id = pay_record.create_alipay_record(cr, uid, record)  # return record['record_id']

post_data = dict()
        post_data['out_trade_no'] = record_id  # out_trade_no= reference of Payment Transaction
post_data['money'] = str(post['money'])
        post_data['auth_code'] = post['auth_code']
        post_data['subject'] = post['subject']

        res = request.registry['payment.acquirer'].make_data_and_post(cr, uid, post_data, context)  # 處理數據並post到阿里
if res:
            res_db = request.registry['payment.transaction'].pay_record_to_db(cr, uid, res, context)
if res_db:
                return_pay_msg['return_code'] = 'SUCCESS'
return_pay_msg['return_msg'] = u'支付成功並寫入數據庫'
return return_pay_msg
else:
            return_pay_msg['return_msg'] = u'支付處理出現問題!查詢數據處理模塊狀態.'
return return_pay_msg
else:
        return_pay_msg['return_msg'] = u'請檢查post的參數,一定要包括orderID、money、auth_code、subject!'
print return_pay_msg['return_msg']
print return_pay_msg
return return_pay_msg

alipay.py(跟支付寶交互的處理)


def encode_dict(self, params):  # 處理編碼問題,都是設置成utf-8
return {k: six.u(v).encode('utf-8')
if isinstance(v, str) else v.encode('utf-8')
if isinstance(v, six.string_types) else v
for k, v in six.iteritems(params)}

def make_data_and_post(self, cr, uid, post_data, context=None):
    ids = self.search(cr, uid, [('provider', '=', 'alipay')], context=context)
    tz = timezone(country_timezones('cn')[0])  # 獲取當前時區
now_cst = datetime.datetime.now(tz)  # 根據當前時區生產時間
biz_content = "{\"out_trade_no\":\""+post_data['out_trade_no']+"\","
biz_content += "\"scene\":\"bar_code\","
biz_content += "\"auth_code\":\""+post_data['auth_code']+"\","
biz_content += "\"total_amount\":\"" + post_data['money'] +"\",\"discountable_amount\":\"0.00\","
biz_content += "\"subject\":\""+post_data['subject']+"\",\"body\":\"test\","
biz_content += "\"goods_detail\":[{\"goods_id\":\"apple-01\",\"goods_name\":\"ipad\",\"goods_category\":\"7788230\",\"price\":\"88.00\",\"quantity\":\"1\"},{\"goods_id\":\"apple-02\",\"goods_name\":\"iphone\",\"goods_category\":\"7788231\",\"price\":\"88.00\",\"quantity\":\"1\"}],"
biz_content += "\"operator_id\":\"op001\",\"store_id\":\"pudong001\",\"terminal_id\":\"t_001\","
biz_content += "\"timeout_express\":\"5m\"}"
del post_data['out_trade_no']  # 公共請求參數不需要
del post_data['auth_code']  # 公共請求參數不需要
del post_data['money']  # 公共請求參數不需要
del post_data['subject']
if ids:
        acquirer = self.browse(cr, uid, ids[0], context=None)
        post_data.update(app_id='2015052600089077')
        post_data.update(charset='UTF-8')
        post_data.update(method='alipay.trade.pay')
        post_data.update(timestamp=now_cst.strftime("%Y-%m-%d %H:%M:%S"))
        post_data.update(version='1.0')
        post_data.update(sign_type='RSA')
        post_data.update(biz_content=biz_content)
        cpd = util.params_filter(post_data)
if cpd:
            sign = util.build_mysign(cpd, sign_type='RSA')
            post_data.update(sign=sign)
try:
                back_info = self.post_alipay(cr, uid, post_data, acquirer.environment, context=None)
return back_info
except Exception, e:
return e
else:
return u'組合字符串有問題!'
else:
return u'沒有創建支付寶支付模式'

def post_alipay(self, cr, uid, post_data, environment, context=None):
    alipay_url = self.get_alipay_urls(cr, uid, environment, context=None)
    pay_state_info = self.post_to_alipay_url(alipay_url, post_data)
return pay_state_info

def post_to_alipay_url(self, url, data):
    headers = {'Content-type': 'application/json;charset=utf-8'}
    data = self.encode_dict(data)
# url_values = urllib.urlencode(self.encode_dict(data))
    # url_values = util.params_filter1(data)
    # print "==========url_values=========="
    # print url_values
    # res = Request(url, url_values, headers)
    # try:
    #     rsp = urlopen(res)
    #     redirect_url = rsp.geturl()
    #     print '===========redirectUrl========='
    #     print redirect_url
    #     the_back_info = rsp.read()
    #     print '===========the_back_info========'
    #     print the_back_info
    #     rsp.close()
    #     return the_back_info
    # except URLError, e:
    #     if hasattr(e, 'reason'):
    #         print u'不能訪問到達改服務器'
    #         print u'原因是:', e.reason
    #         return e.reason
    # except HTTPError, e:
    #     print u'錯誤代碼:', e.code
    #     return e.code
data = urllib.urlencode(data)
# rsp = requests.post(url, data=json.dumps(data), headers=headers)
rsp = requests.get(url, params=data, headers=headers)
if rsp.status_code != 200:
return False
if rsp.text:
return rsp.text

util.py(生產傳輸參數,以及sign的生產)


def params_filter(params):
    ks = params.keys()
    ks.sort()
    newparams = {}
    prestr = ''
for k in ks:
        v = params[k]
# k = smart_str(k, 'utf-8')
if k not in 'sign' and v != '':
            newparams[k] = v
# newparams[k] = smart_str(v, 'utf-8')
prestr += '%s=%s&' % (k, newparams[k])
    prestr = prestr[:-1]
return prestr


def build_mysign(prestr, sign_type='MD5'):
if sign_type == 'MD5':  # 這裏的md5估計用不了,後面有需求再修改
return md5_constructor(prestr).hexdigest()
elif sign_type == 'RSA':
# 打開私匙文件並轉換成python rsa的private key格式
with open(r'D:\alipaykey\rsa_private_key.pem') as priv_key:
            privkey = priv_key.read()
        privatekey = rsa.PrivateKey.load_pkcs1(privkey)
        signature = rsa.sign(prestr, privatekey, 'SHA-1')
        sign = base64.b64encode(signature)
return sign

不得不說這裏的難點,就是python的rsa,在生產支付寶的sign過程中嘗試了很多,首先了解一下python的rsa,附上rsa官網:https://stuvel.eu/python-rsa-doc/index.html


一般情況就是:

>>> (pubkey,privkey)=rsa.newkeys(512)   # 使用python rsa生產的公鑰和私鑰>>> message='Go left at the blue tree'>>> signature=rsa.sign(message,privkey,'SHA-1')   # 根據私鑰生成的SHA-1的簽名

解碼sign:

>>> message='Go left at the blue tree'>>> rsa.verify(message,signature,pubkey)True



但是現在我們的情況是我們已經用openssl生產了自己的私鑰和公鑰,這也是支付寶要求用openssl生產的,我們還是用openssl生產吧,但是問題來了,python的rsa跟openssl的私鑰、公鑰的格式不一樣的,大家可以嘗試打印一下rsa生產的key,它是一大串的數字串,但是openssl生產的是有數字、符號、字母等等的字符串!我在這裏卡了很久,後面還是在同事幫忙下找到了解決方法:rsa.PrivateKey.load_pkcs1() 以及rsa.PublicKey.load_pkcs1() 方法,專門是用來跟openssl生產的key交互的,其實rsa是可以生產openssl格式的key,這裏具體不去做嘗試了,具體詳細看官網!

with open(r'D:\alipaykey\rsa_private_key.pem') as priv_key:
            privkey = priv_key.read()
        privatekey = rsa.PrivateKey.load_pkcs1(privkey)
        signature = rsa.sign(prestr, privatekey, 'SHA-1')

這樣生產signture是符合支付寶的sign簽名要求的,以上還是一個開始,因爲後面有

wKiom1cot9yAuQuoAAAqNYKqUF4555.png

spacer.gif等等要做開發的。


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