Skip to main content

统一支付基础设施 SDK,支持微信支付和支付宝

Project description

pay-kit

统一支付基础设施 SDK,支持微信支付和支付宝商户。一个 SDK 即可处理支付、转账、余额查询。

特性

  • 双平台支持 — 微信支付 V3 + 支付宝 V3
  • 多种支付方式 — 扫码、JSAPI、H5、App、电脑网站
  • 统一接口 — PayProvider / WithdrawProvider / WalletProvider 三个 ABC
  • 类型安全 — 全面类型注解,mypy strict 通过
  • 纯异步 — 基于 httpx,async/await 原生支持
  • 安全 — RSA-SHA256 签名/验签、AES-GCM 回调解密、SecretStr 敏感字段保护

安装

pip install pay-kit

快速开始

微信支付 — Native 扫码支付

from pay_kit.providers.wechat import WechatPay, WechatPayConfig
from pay_kit.models import PaymentRequest
from pay_kit.types import Fen

config = WechatPayConfig(
    appid="wx_your_appid",
    mch_id="your_mch_id",
    private_key=open("apiclient_key.pem").read(),      # 商户 API 私钥
    cert_serial_no="YOUR_CERT_SERIAL_NO",               # 商户证书序列号
    wechat_public_key=open("wechat_public_key.pem").read(),  # 微信支付公钥
    wechat_public_key_id="YOUR_PUB_KEY_ID",
    apiv3_key="your_apiv3_key",
    notify_url="https://your-domain.com/callback/wechat",
)

async with WechatPay(config) as pay:
    # 创建支付订单
    result = await pay.create_payment(
        PaymentRequest(out_trade_no="ORDER_001", total_amount=Fen(100), subject="商品名称")
    )
    print(result.credential["code_url"])  # 用此 URL 生成二维码

支付宝 — 当面付扫码支付

from pay_kit.providers.alipay import Alipay, AlipayConfig
from pay_kit.models import PaymentRequest
from pay_kit.types import Fen

config = AlipayConfig(
    app_id="your_app_id",
    private_key=open("app_private_key.pem").read(),     # 应用私钥
    alipay_public_key=open("alipay_public_key.pem").read(),  # 支付宝公钥
    notify_url="https://your-domain.com/callback/alipay",
)

async with Alipay(config) as pay:
    result = await pay.create_payment(
        PaymentRequest(out_trade_no="ORDER_001", total_amount=Fen(100), subject="商品名称")
    )
    print(result.credential["qr_code"])  # 二维码 URL

支付方式

微信支付

async with WechatPay(config) as pay:
    # Native 扫码支付(通用接口)
    result = await pay.create_payment(request)
    # credential: {"code_url": "weixin://wxpay/..."}

    # JSAPI 公众号/小程序支付
    result = await pay.create_jsapi_payment(request, openid="user_openid")
    # credential: {"appId", "timeStamp", "nonceStr", "package", "signType", "paySign"}

    # H5 手机浏览器支付
    result = await pay.create_h5_payment(request, payer_client_ip="1.2.3.4")
    # credential: {"h5_url": "https://wx.tenpay.com/..."}

    # App 支付
    result = await pay.create_app_payment(request)
    # credential: {"appId", "partnerId", "prepayId", "package", "nonceStr", "timeStamp", "sign"}

支付宝

async with Alipay(config) as pay:
    # 当面付扫码支付(通用接口)
    result = await pay.create_payment(request)
    # credential: {"qr_code": "https://qr.alipay.com/..."}

    # 电脑网站支付
    result = await pay.create_page_payment(request, return_url="https://your-site.com/return")
    # credential: {"pay_url": "https://openapi.alipay.com/..."}

    # 手机网站支付
    result = await pay.create_wap_payment(request, return_url="https://your-site.com/return")
    # credential: {"pay_url": "https://openapi.alipay.com/..."}

    # App 支付
    result = await pay.create_app_payment(request)
    # credential: {"order_str": "alipay_sdk=..."}

通用操作

查询、关单、退款等操作两个平台用法一致:

# 查询订单
result = await pay.query_payment("ORDER_001")
print(result.status)  # PaymentStatus.PAID

# 关闭订单
await pay.close_payment("ORDER_001")

# 发起退款
from pay_kit.models import RefundRequest
refund = await pay.refund(
    RefundRequest(
        out_trade_no="ORDER_001",
        out_refund_no="REFUND_001",
        total_amount=Fen(100),
        refund_amount=Fen(50),
    )
)

# 查询退款
refund = await pay.query_refund("REFUND_001")

转账

from pay_kit.models import WithdrawRequest

async with WechatPay(config) as pay:
    # 商家转账到零钱
    result = await pay.create_withdrawal(
        WithdrawRequest(
            out_withdrawal_no="TRANSFER_001",
            amount=Fen(1000),
            recipient="user_openid",         # 微信: openid / 支付宝: user_id
            description="佣金提现",
        )
    )
    print(result.status)  # WithdrawStatus.PENDING

    # 查询转账状态
    result = await pay.query_withdrawal("TRANSFER_001")

余额查询

async with WechatPay(config) as pay:
    balance = await pay.query_balance()
    print(f"可用余额: {balance.available} 分")
    print(f"待结算: {balance.pending} 分")

回调验签

# FastAPI 示例
from fastapi import Request

@app.post("/callback/wechat")
async def wechat_callback(request: Request):
    headers = dict(request.headers)
    body = await request.body()

    async with WechatPay(config) as pay:
        event = await pay.verify_callback(headers, body)

    print(event.event_type)     # "TRANSACTION.SUCCESS"
    print(event.out_trade_no)   # "ORDER_001"
    print(event.trade_no)       # 微信交易号
    print(event.raw)            # 完整回调数据

    return {"code": "SUCCESS"}

异常处理

from pay_kit.exceptions import (
    PayKitError,       # 所有异常基类
    ConfigError,       # 配置错误
    NetworkError,      # 网络超时/连接失败
    SignatureError,    # 签名验证失败
    PaymentError,      # 支付业务错误
    WithdrawError,     # 转账业务错误
    WalletError,       # 余额查询错误
)

try:
    result = await pay.create_payment(request)
except NetworkError:
    # 网络问题,可重试
    pass
except SignatureError:
    # 签名验证失败,响应不可信
    pass
except PaymentError as e:
    # 业务错误
    print(e.error_code)      # 支付商错误码,如 "ORDER_CLOSED"
    print(e.provider_name)   # "wechat" 或 "alipay"

金额类型

pay-kit 使用 Fen(分)作为金额单位,避免浮点精度问题:

from pay_kit.types import Fen, Yuan, fen_to_yuan, yuan_to_fen

amount = Fen(100)                    # 100 分 = 1 元
yuan = fen_to_yuan(Fen(100))         # Yuan("1.00")
fen = yuan_to_fen(Yuan("1.00"))      # Fen(100)

开发

git clone https://github.com/Xinzz995/pay-kit.git
cd pay-kit
uv sync

uv run pytest                        # 运行测试
uv run pytest --cov=pay_kit          # 覆盖率
uv run ruff check .                  # Lint
uv run mypy src/                     # 类型检查

许可证

MIT

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

pay_py_kit-0.2.0.tar.gz (80.1 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

pay_py_kit-0.2.0-py3-none-any.whl (21.9 kB view details)

Uploaded Python 3

File details

Details for the file pay_py_kit-0.2.0.tar.gz.

File metadata

  • Download URL: pay_py_kit-0.2.0.tar.gz
  • Upload date:
  • Size: 80.1 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.11.15

File hashes

Hashes for pay_py_kit-0.2.0.tar.gz
Algorithm Hash digest
SHA256 3aa3697db7bcc267624875c297c591513532c0fd0fd183ba849158d8fdf7fbc7
MD5 bb72780b9b19b5494bac4258a4344c5f
BLAKE2b-256 056870cf6b47cda28923df21ddfc5e2bfe92f355073d3fab01c2583795a95153

See more details on using hashes here.

File details

Details for the file pay_py_kit-0.2.0-py3-none-any.whl.

File metadata

  • Download URL: pay_py_kit-0.2.0-py3-none-any.whl
  • Upload date:
  • Size: 21.9 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.11.15

File hashes

Hashes for pay_py_kit-0.2.0-py3-none-any.whl
Algorithm Hash digest
SHA256 5e985f621e4513d16364f7dfa92c006a0d7261f7f2d62ee3ebd874dfb48d290e
MD5 56d8a3a5fe31f129e5cb124f2141af46
BLAKE2b-256 e7657d7e838c08a632a0e0c0da52594e0c3bdac6d028709ae76516df1ec0af1e

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page