1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131
| import hashlib import hmac import json import time import requests from urllib.parse import urlencode, unquote from Crypto.Signature import PKCS1_v1_5 from Crypto.Hash import SHA256 from Crypto.PublicKey import RSA import base64 import qrcode from PIL import Image import os
class AlipayPreorderClient: def __init__(self, app_id, merchant_private_key, alipay_public_key): """初始化支付宝预收单客户端""" self.app_id = app_id self.merchant_private_key = merchant_private_key self.alipay_public_key = alipay_public_key self.gateway = "https://openapi.alipay.com/gateway.do" self.format = "JSON" self.charset = "utf-8" self.sign_type = "RSA2"
def generate_sign(self, params, private_key): """生成RSA2签名""" params_to_sign = {k: v for k, v in params.items() if k != "sign" and v is not None} sorted_params = sorted(params_to_sign.items(), key=lambda x: x[0]) string_to_sign = "&".join([f"{k}={v}" for k, v in sorted_params]) private_key = private_key.replace("-----BEGIN PRIVATE KEY-----", "").replace("-----END PRIVATE KEY-----", "").replace("\n", "") private_key_bytes = base64.b64decode(private_key) key = RSA.import_key(private_key_bytes) h = SHA256.new(string_to_sign.encode('utf-8')) signer = PKCS1_v1_5.new(key) signature = signer.sign(h) return base64.b64encode(signature).decode('utf-8')
def create_preorder(self, out_trade_no, total_amount, subject): """创建预收单并获取二维码链接""" common_params = { "app_id": self.app_id, "method": "alipay.trade.precreate", "format": self.format, "charset": self.charset, "sign_type": self.sign_type, "timestamp": time.strftime("%Y-%m-%d %H:%M:%S", time.localtime()), "version": "1.0", } biz_content = { "out_trade_no": out_trade_no, "total_amount": total_amount, "subject": subject, "timeout_express": "30m", "product_code": "QR_CODE_OFFLINE" } common_params["biz_content"] = json.dumps(biz_content, ensure_ascii=False) common_params["sign"] = self.generate_sign(common_params, self.merchant_private_key) url = f"{self.gateway}?charset={self.charset}" response = requests.post(url, data=common_params) result = response.json() if 'alipay_trade_precreate_response' in result and result['alipay_trade_precreate_response'].get('code') == '10000': qr_code = result['alipay_trade_precreate_response']['qr_code'] return qr_code else: print(f"预收单创建失败: {result}") return None
def generate_qr_code(qr_url, save_path="alipay_payment_code.png"): """生成二维码图片""" decoded_url = unquote(qr_url) qr = qrcode.QRCode( version=1, error_correction=qrcode.constants.ERROR_CORRECT_L, box_size=10, border=4, ) qr.add_data(decoded_url) qr.make(fit=True) img = qr.make_image(fill_color="black", back_color="white") img.save(save_path) print(f"二维码已保存至: {os.path.abspath(save_path)}") return save_path
def display_qr_code(image_path): """显示二维码图片""" try: img = Image.open(image_path) img.show() except Exception as e: print(f"显示二维码失败: {e}") print(f"请手动打开: {image_path}")
if __name__ == "__main__": APP_ID = "2021005164660117" MERCHANT_PRIVATE_KEY = """-----BEGIN PRIVATE KEY----- MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQClh0WVsYQzoXfYR4eb5DTQKsjBnCcKSUplT3P+XR6YFRzjQvISxNNKJCRX3Ia/XRQwsOSzx4DfhxjwDcZFg3o52TbcoJej0aSK6tjQvJ7W5V3FmKW32mZuyq1Ni2ZOTmGQwydLWurt5PW3x1b32+Bs6CoNxiVUsVFUw+zb37+Vq5G2AfQcsfkYNR8DcXqfvlP9fuD7H2I0kwdxgCdea2WUZGgiVxwWk6IMtKnXejmYdgbZcmB4wEeGL0BTs2tMwofcvo68heLuBxr7fZFXVz1UIPC6XoaY74MLu4BvHqrudeSwSLCOkiblrTFfPglD2mhYyauAJFLgc1st2OwMgQxPAgMBAAECggEACk63HZA1TEXEwboKjsGSLFhNsgi4QaK4uEBPV8qSqiO+bcRwcIzDH33KqZH47hesty98vlkxBDpUajZhX1jFlq6ZBPoXF0NpvKDNKYplVbposXJE94LpGAMU8Zw5nayx1KLiYoXh1TiJuIz4NG0Dt6RpYfwxvOlhyCZ/LF3tfzNa0o9COSG/0XqUdH3LITwBS9mF9joo4WBjQxi5+yGh48cLuj+2kLzXNEybw/9pB0N+kABmrIfZttnDs7GxFcGaar8YUamN7a7KWRWcC4BH1r23D2ngZS9FmBm4kYKySq1EOLgs8hjj5kvwqsz83uPTQDDOdhCOOq1boYKa5XjnqQKBgQD1OSOmxUpuA6mBDj5wkGe3r+HWlnpW7UwfNDrNX4P7howplxR6BCJhOsuf4cMIJmIDjXiWO8kIf4uMFRW6mNUrZYG6DRui3UYuMqtiqVjAUdX8AvXhRdyQx8ELVw7aghkTsaFe2myK0Zmx3zGlGKT4y2L6NIShe51BZuzPd3gkcwKBgQCszYigfx02MVA3U9fKk2A81nAzXw3b0jTdGxV74PGDLtg2bvEIi0wO4NoK3N0UjDQkMuLZ7MOqwGo1gHUeM2nea3mcnryj2oKR1Y7NcRAoImAryPogxdPap+MUeccvf4XZFndKCJdmzyVw5oH3p27DC2vrxIC/roHFykt/gIjdtQKBgGVO1Na6HRS0OJvTiaIxVlgBtphTlHlDEba2ejCMbFdGb7Ni8heyi42Fn8gOmedNDCMRmCbgzh3Pq5QUxeRP7Yk/J0f40FkJd0vwrPNWqQ7TAEdb5b7KgOPjUnJf5ggJxVhogxVPwZXcH9XnMnhVZRpP1DUv6zdXfVEet2jCn4TXAoGBAJ40uo6+ch8ofNl6wIkt7qEkbqsJrqV/yXhZEI1O/65r1/XWEoURCzxf7iCd3yatyhsOH5UHaIjPCy4agp940MeavEeBKRIWvw4HaGt8xR8JgeT0ZtRUaka5CHS5nXxGE2QSZnp4bSzqH8xCreDwAL8/mLnNOVbEzPkp4X9FTYk1AoGBANy9FPHWgIDNiVZCeZUJJH7UTsplqFJyvnlW1cSIWr2uOmAxbNW8jmFyUt+qNTLhplS2U4H2nkXAskb591xWZXFlUtr8dlrDmKRCUE/d1aQJU8gpEoSFDsQ/XQec/RtN12rvCs2pk/Y71hZp+Jwz0LPtCNkqLxoG5JkAz2HwY4W -----END PRIVATE KEY-----""" ALIPAY_PUBLIC_KEY = """-----BEGIN PUBLIC KEY----- MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAhDhkT2FHjZBJhiiOPI8sUfp5CLc98yFY46g8CzM/BY2rXDkznjm00Ij+rCP4X9HSibq9T0PJ9l9Fs4LX0hOpN9D/v4mdvqzbLgGuwVNAD+KR6cxAv0xn3mil9FfTyne9FUAyWj+pSxZXbsh3vKV3dXvDi0rlzbqtZG+jEetcm5+FUpeezHpCdXaPZbZ9BmsWu3jf/JxorGOkvgpy/RGp1MIY3hW+Acdkb4CqE64IQH2uaclj4ubd+DhEjTCJX02SX7WS59TXQipaDRznhc5LlIPsFwPmmFwafrDC5abkh0D5nawm6yVn6hoZSg2gpWeS1DqwVQAQWkq+XdwIJJlgMQIDAQA -----END PUBLIC KEY-----""" client = AlipayPreorderClient(APP_ID, MERCHANT_PRIVATE_KEY, ALIPAY_PUBLIC_KEY) out_trade_no = f"PREORDER_{int(time.time())}" qr_code_url = client.create_preorder( out_trade_no=out_trade_no, total_amount="1.00", subject="测试商品" ) if qr_code_url: qr_image = generate_qr_code(qr_code_url) display_qr_code(qr_image)
|