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)

完整示例

examples/ 目录包含可运行的完整代码:

文件 场景
wechat_all_methods.py 微信全场景(4 种支付 + 查询/关单/退款/转账/余额)
alipay_all_methods.py 支付宝全场景(4 种支付 + 查询/关单/退款/转账/余额)
fastapi_server.py FastAPI 生产级集成(多 Provider + 回调 + 异常处理)
multi_provider.py 多支付商统一接口(PayProvider ABC 多态)
uv sync --group examples
cp examples/.env.example examples/.env
# 编辑 .env 填入商户配置
uv run python examples/wechat_all_methods.py

详见 examples/README.md

开发

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.3.1.tar.gz (90.5 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.3.1-py3-none-any.whl (22.8 kB view details)

Uploaded Python 3

File details

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

File metadata

  • Download URL: pay_py_kit-0.3.1.tar.gz
  • Upload date:
  • Size: 90.5 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: uv/0.11.6 {"installer":{"name":"uv","version":"0.11.6","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}

File hashes

Hashes for pay_py_kit-0.3.1.tar.gz
Algorithm Hash digest
SHA256 0cd37e1a68d1410f974fa27f6e0d0ce93837466af311ae7fd07d1079641dceb2
MD5 358b903310a6dd924986a71e28cdc02d
BLAKE2b-256 49b3df177245c29e7957b5b629ee78513457b99cb0103166c760cc38556338df

See more details on using hashes here.

File details

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

File metadata

  • Download URL: pay_py_kit-0.3.1-py3-none-any.whl
  • Upload date:
  • Size: 22.8 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: uv/0.11.6 {"installer":{"name":"uv","version":"0.11.6","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}

File hashes

Hashes for pay_py_kit-0.3.1-py3-none-any.whl
Algorithm Hash digest
SHA256 5def71a307338a7604ad9473b6cfc695f786de0baa4be9a7f13113518fcd2e44
MD5 4c4705a7c7538bdbc1f2dbebc96bdd3a
BLAKE2b-256 3c074cddfc28670c6f2052b8b8d00f7fb2c146dc9379b9027480aa1e5934e34e

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