Skip to main content

dwy-wechatpay-notify

独立微信支付来源包(0.1.1):复用 wechatpayv3[async]==2.0.4 的公开 callback(headers, body) 验签解密,把付款和退款结果转成 dwy_notify.events.NotificationEvent。不依赖宿主支付模块,不实现 RSA/AES、业务账本、权益变更或群消息发送。

本包采用 MIT License。微信支付 SDK wechatpayv3==2.0.4 同样采用 MIT,具体版权声明以各发行包为准。

已有支付后台

已有官方回调入口的项目直接使用 verifier,不重复注册本包路由。SDK 客户端、商户私钥、APIv3 密钥、公钥/平台证书全部由宿主配置;在 SDK 客户端有效上下文内注入它的同步公开 callback。本包不读取环境变量、不复制密钥、不调用 SDK 私有 core。

from dwy_wechatpay_notify import (
    PaymentNotificationContext,
    WechatPayNotificationVerifier,
    WechatPayNotifyConfig,
    wechatpay_notification_event,
)


async def handle_callback(headers, raw_body, sdk_client, payment_service, durable_sink):
    """由宿主传入已打开的 SDK 客户端、原始 bytes 和持久接收器。"""
    config = WechatPayNotifyConfig(mchid="1900000001", appid="wx123", scope="shop-production")
    verified = await WechatPayNotificationVerifier(config, callback=sdk_client.callback).verify(headers, raw_body)
    # 宿主核对本地订单/金额并完成业务提交;持久 outbox 应与业务事务一起写入。
    confirmed = await payment_service.apply_verified_notification(verified)
    event = wechatpay_notification_event(
        confirmed,
        scope=config.scope,
        context=PaymentNotificationContext(description="基础版月付", outcome="权益已确认"),
    )
    await durable_sink(event)

payment_service 与 durable_sink 是宿主注入对象,示例不定义业务账本。主动查单、补单或对账时构造 ConfirmedWechatPayResult:付款需 event_type="TRANSACTION.SUCCESS"、order_no、transaction_id、整数分 amount_fen、trade_type、trade_state="SUCCESS";退款另需 refund_no、refund_id、refund_fen、与事件一致的 refund_status。查单没有官方回调 ID 时保持 provider_event_id=None。

收到已验证官方事件不证明本地已入账。宿主必须核对订单、币种、原金额与状态,并由自己的事务确定权益。REFUND.ABNORMAL、REFUND.CLOSED 只表示异常/关闭,不能当作退款成功。退款回调可能没有 appid,始终核验 mchid;有 appid 时同时核验。

新项目:可选 FastAPI 安装器

安装包的 [fastapi] extra 后调用以下装配函数;生产必须传入持久化 EventSink,不得用只发 HTTP 群消息的函数替代持久接受。sink(event) 返回 True 表示新接受,False 表示之前已接受的重复,二者均确认;异常返回 HTTP 503,微信可重试。本模块不在验签前用内存 receipt 吞掉业务重试。

from dwy_wechatpay_notify import (
    WechatPayNotificationVerifier,
    WechatPayNotifyConfig,
    install_wechatpay_notifications,
)


def configure_callbacks(app, sdk_client, durable_sink):
    """宿主 lifespan 保持 SDK 客户端存活,关闭资源仍由宿主负责。"""
    config = WechatPayNotifyConfig(mchid="1900000001", appid="wx123", scope="shop-production")
    install_wechatpay_notifications(
        app,
        config,
        verifier=WechatPayNotificationVerifier(config, callback=sdk_client.callback),
        sink=durable_sink,
    )

默认接收地址示例:http://localhost:8000/webhooks/wechatpay;生产应配置真实公网 HTTPS,例如 https://payments.example.com:443/webhooks/wechatpay。可通过 config.path 更改。安装器流式读取请求,默认最多 65536 bytes;超限 HTTP 413,验签/身份/协议失败 HTTP 400,持久接受成功或重复 HTTP 204。只交给 SDK 一次原始 bytes,不改变宿主 lifespan、不启动或关闭其他应用。

安全与幂等

0.1.1 起,外部项目可以通过 PaymentNotificationContext.extra_fields 提供自定义展示字段:

from dwy_notify import NotificationField
from dwy_wechatpay_notify import ConfirmedWechatPayResult, PaymentNotificationContext, wechatpay_notification_event

result = ConfirmedWechatPayResult(
    event_type="TRANSACTION.SUCCESS", order_no="order123", transaction_id="wx123",
    amount_fen=1, trade_type="NATIVE", trade_state="SUCCESS",
)
event = wechatpay_notification_event(
    result, scope="shop-preview",
    context=PaymentNotificationContext(
        description="基础套餐", outcome="权益已发放",
        extra_fields=(
            NotificationField(label="客户编号", value="customer-001"),
            NotificationField(label="项目名称", value="示例项目"),
        ),
    ),
)

最多 8 项,每项标签 1–32、值 1–256 字符,均为单行纯文本。禁止重复标签及“订单号、金额、退款金额、业务结果”等固定标签;字段不会合并进官方 data 或改变去重键。库不查询用户表,也不自动序列化业务对象。字段是否允许包含个人资料及是否脱敏由宿主显式决定;不得传入密码、密钥或原始回调。入队前渲染正文,重试沿用快照。NotificationEvent.data 不会自动成为群消息。

传入字段时,固定金融事实与业务结果优先,其次附加字段,最后商品描述;总预算仍为 1800 UTF-8 字节,附加展示过长会标记截断或省略。未传字段时保持 0.1.0 的正文兼容行为。

  • 配置显式注入,商户/应用身份非空,scope 最长 128 字符;不同商户/应用必须使用不同 scope。
  • 付款键 wechat:payment:{order_no}:success;退款键 wechat:refund:{refund_no}:{SUCCESS|ABNORMAL|CLOSED}。回调与主动查单使用同一业务键;sink 按 source、scope、event_id 持久幂等。
  • 事件 data 仅包含类型化白名单字段;不自动转发 payer/openid、邮箱、手机号、密钥、签名或原文。商品与业务结果不能夹带个人信息;需要展示的宿主资料须显式选择 extra_fields,不接受任意账号对象。
  • 通知正文严格不超过 1800 UTF8 bytes,不截断金融标识。未传自定义字段时沿用原有商品/业务结果整项省略规则。金额用整数分格式化。
  • WECHATPAY/SIGNTEST/ 不是交易,安全拒绝;SDK 的异常统一转成 WechatPayVerificationError,不携带原文或密钥。宿主不得给 SDK 配置记录回调原文的日志器。

开发与验收

执行本目录 pytest 运行全部用例,使用固定测试驱动与本地临时 RSA 密钥/AESGCM,均不访问微信/企微网络。tests/TEST_CASES.md 记录覆盖边界。tests/wheel_smoke.py 面向已安装 wheel,验证独立核心导入及事件合同。正式发行必须使用 GitHub Actions OIDC;本地构建仅做临时 wheel 验收,不替代发布工作流。

Metadata

Release files for dwy-wechatpay-notify 0.1.1

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Built distribution (wheel)

Table of built distributions (wheels) for dwy-wechatpay-notify 0.1.1
File Interpreter ABI Platform Actions
dwy_wechatpay_notify-0.1.1-py3-none-any.whl Python 3 none any Details for dwy_wechatpay_notify-0.1.1-py3-none-any.whl

Release files / dwy_wechatpay_notify-0.1.1-py3-none-any.whl

Download URL dwy_wechatpay_notify-0.1.1-py3-none-any.whl
Size 14.1 kB
Tags Python 3
SHA-256 checksum
How to use checksums
04160effbe942229ab177f5f11ccd1f5b0eaba3c82d1d4b4415369a1af8cebbc
BLAKE2b-256 checksum
How to use checksums
abf4ead65bb2a59899341b9cccd7f871009720d1fe6965427ccad6b30733312f
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.16

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Nov 2, 2026.

Transparency log

Security for dwy-wechatpay-notify 0.1.1

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

Full provenance

All 1 file in this release has been uploaded with provenance metadata.

Attestation for dwy_wechatpay_notify-0.1.1-py3-none-any.whl

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Nov 2, 2026.

Transparency log

A note on package security

PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.

To learn more about protecting yourself from malicious actors, visit our package security documentation.

Release history Release notifications | RSS feed

This release

0.1.1 This release

1 release file Full provenance

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page