[後端開發]支付寶支付介面除錯 (Python v3.6)

chaseSpace-L發表於2018-05-25

寫在前面:

    講真,一開始接到這個任務我是拒絕的。因為支付寶官方沒有提供Python的SDK環境,只有JAVA/PHP/.NET三種語言的SDK,這意味著簽名&驗籤、HTTP介面請求等操作全都要自己手動實現,就算支付寶提供了簽名、驗籤的演算法說明,但僅靠它的文字描述就寫出一個符合支付寶想法的演算法很明顯“任重道遠”,我當然不會去嘗試這條路。

    幸運的是,github總能給我驚喜,搜尋“alipay python sdk”結果第一個就是,兩百多顆星,這意味著接下來的路平坦許多。

正文:

   我接到的需求是做二維碼支付(不同於支付寶官方的當面付/APP支付/手機網站支付/電腦網站/支付/等),流程如下:

   接收商品名稱資訊、訂單金額、訂單號 》》》請求“支付寶預付訂單建立介面”根據返回的URL生成二維碼》》》 使用者掃碼支付》》》一定時間內輪詢訂單狀態,若超時未支付則關閉訂單。

    操作(二維碼支付): 

pip install python-alipay-sdk --upgrade
from alipay import AliPay
import time,qrcode


alipay_public_key_string = '''-----BEGIN PUBLIC KEY-----
    YOUR_ALIPAY_PUBLIC_KEY
-----END PUBLIC KEY-----'''


app_private_key_string = '''-----BEGIN RSA PRIVATE KEY-----
    YOUR_APP_PRIVATE_KEY
-----END RSA PRIVATE KEY-----'''

#注意:一個是支付寶公鑰,一個是應用私鑰

APP_ID = '2018052160210122'
NOTIFY_URL = "https://your_domain/alipay_callback"


def init_alipay_cfg():
    '''
    初始化alipay配置
    :return: alipay 物件
    '''
    alipay = AliPay(
        appid=APP_ID,
        app_notify_url=NOTIFY_URL,  # 預設回撥url
        app_private_key_string=app_private_key_string,
        alipay_public_key_string=alipay_public_key_string,  # 支付寶的公鑰,驗證支付寶回傳訊息使用,不是你自己的公鑰,
        sign_type="RSA2",  # RSA 或者 RSA2
        debug = False  # 預設False ,若開啟則使用沙盒環境的支付寶公鑰
    )
    return alipay


def get_qr_code(code_url):
    '''
    生成二維碼
    :return None
    '''
    #print(code_url)
    qr = qrcode.QRCode(
        version=1,
        error_correction=qrcode.constants.ERROR_CORRECT_H,
        box_size=10,
        border=1
    )
    qr.add_data(code_url)  # 二維碼所含資訊
    img = qr.make_image()  # 生成二維碼圖片
    img.save(r'C:\Users\SEEMORE\Desktop\qr_test_ali.png')
    print('二維碼儲存成功!')


def preCreateOrder(subject:'order_desc' , out_trade_no:int, total_amount:(float,'eg:0.01')):
    '''
    建立預付訂單
    :return None:表示預付訂單建立失敗  [或]  code_url:二維碼url
    '''
    result = init_alipay_cfg().api_alipay_trade_precreate(
        subject=subject,
        out_trade_no=out_trade_no,
        total_amount=total_amount)
    print('返回值:',result)
    code_url = result.get('qr_code')
    if not code_url:
        print(result.get('預付訂單建立失敗:','msg'))
        return
    else:
        get_qr_code(code_url)
        #return code_url


def query_order(out_trade_no:int, cancel_time:int and 'secs'):
    '''
    :param out_trade_no: 商戶訂單號
    :return: None
    '''
    print('預付訂單已建立,請在%s秒內掃碼支付,過期訂單將被取消!'% cancel_time)
    # check order status
    _time = 0
    for i in range(10):
        # check every 3s, and 10 times in all

        print("now sleep 2s")
        time.sleep(2)

        result = init_alipay_cfg().api_alipay_trade_query(out_trade_no=out_trade_no)
        if result.get("trade_status", "") == "TRADE_SUCCESS":
            print('訂單已支付!')
            print('訂單查詢返回值:',result)
            break

        _time += 2
        if _time >= cancel_time:
            cancel_order(out_trade_no,cancel_time)
            return


def cancel_order(out_trade_no:int, cancel_time=None):
    '''
    撤銷訂單
    :param out_trade_no:
    :param cancel_time: 撤銷前的等待時間(若未支付),撤銷後在商家中心-交易下的交易狀態顯示為"關閉"
    :return:
    '''
    result = init_alipay_cfg().api_alipay_trade_cancel(out_trade_no=out_trade_no)
    #print('取消訂單返回值:', result)
    resp_state = result.get('msg')
    action = result.get('action')
    if resp_state=='Success':
        if action=='close':
            if cancel_time:
                print("%s秒內未支付訂單,訂單已被取消!" % cancel_time)
        elif action=='refund':
            print('該筆交易目前狀態為:',action)

        return action

    else:
        print('請求失敗:',resp_state)
        return


def need_refund(out_trade_no:str or int, refund_amount:int or float, out_request_no:str):
    '''
    退款操作
    :param out_trade_no: 商戶訂單號
    :param refund_amount: 退款金額,小於等於訂單金額
    :param out_request_no: 商戶自定義引數,用來標識該次退款請求的唯一性,可使用 out_trade_no_退款金額*100 的構造方式
    :return:
    '''
    result = init_alipay_cfg().api_alipay_trade_refund(out_trade_no=out_trade_no,
                                                       refund_amount=refund_amount,
                                                       out_request_no=out_request_no)

    if result["code"] == "10000":
        return result  #介面呼叫成功則返回result
    else:
        return result["msg"] #介面呼叫失敗則返回原因


def refund_query(out_request_no:str, out_trade_no:str or int):
    '''
    退款查詢:同一筆交易可能有多次退款操作(每次退一部分)
    :param out_request_no: 商戶自定義的單次退款請求識別符號
    :param out_trade_no: 商戶訂單號
    :return:
    '''
    result = init_alipay_cfg().api_alipay_trade_fastpay_refund_query(out_request_no, out_trade_no=out_trade_no)

    if result["code"] == "10000":
        return result  #介面呼叫成功則返回result
    else:
        return result["msg"] #介面呼叫失敗則返回原因


if __name__ == '__main__':
    cancel_order(1527212120)
    subject = "話費餘額充值"
    out_trade_no =int(time.time())
    total_amount = 0.01
    preCreateOrder(subject,out_trade_no,total_amount)

    query_order(out_trade_no,40)

    print('5s後訂單自動退款')
    time.sleep(5)
    print(need_refund(out_trade_no,0.01,111))

    print('5s後查詢退款')
    time.sleep(5)
    print(refund_query(out_request_no=111, out_trade_no=out_trade_no))
    #操作完登入 https://authsu18.alipay.com/login/index.htm中的對賬中心檢視是否有一筆交易生成並退款

        下面是支付寶介面呼叫成功的response示例:

官文:https://docs.open.alipay.com/api_1/
建立預付訂單返回值:
{'code': '10000', 'msg': 'Success', 'out_trade_no': '1527214200', 'qr_code': 'https://qr.alipay.com/bax09560qqw1epttm5i8006e'}

取消訂單返回值示例:
{'code': '10000', 'msg': 'Success', 'action': 'close'(交易已取消), 'out_trade_no': '1527212120', 'retry_flag': 'N',
 'trade_no': '2018052521001004480221282310'}

訂單查詢返回值:
{'code': '10000', 'msg': 'Success', 'buyer_logon_id': 'cha***@icloud.com', 'buyer_pay_amount': '0.01',
 'buyer_user_id': '2088012915825485', 'fund_bill_list': [{'amount': '0.01', 'fund_channel': 'ALIPAYACCOUNT'}],
  'invoice_amount': '0.01', 'out_trade_no': '1527217434', 'point_amount': '0.00', 'receipt_amount': '0.01',
   'send_pay_date': '2018-05-25 11:04:08', 'total_amount': '0.01', 'trade_no': '2018052521001004480221487538',
    'trade_status': 'TRADE_SUCCESS'}

退款返回值示例:
{'code': '10000', 'msg': 'Success', 'buyer_logon_id': 'cha***@icloud.com', 'buyer_user_id': '2088012915825485', 'fund_change': 'Y',
 'gmt_refund_pay': '2018-05-25 10:08:05', 'out_trade_no': '1527211312', 'refund_detail_item_list': [{'amount': '0.01', 'fund_channel': 'ALIPAYACCOUNT'}],
  'refund_fee': '0.01', 'send_back_fee': '0.01', 'trade_no': '2018052521001004480221209563'}
  
退款查詢返回值示例:
{'code': '10000', 'msg': 'Success', 'out_request_no': '111', 'out_trade_no': '1527216203', 'refund_amount': '0.01',
 'total_amount': '0.01', 'trade_no': '2018052521001004480221450113'}
'''

 

-有用可以點個贊-

 

相關文章