当前原型使用模拟支付,只能验证订单和打印任务流转。真实公开收费前,必须接入微信支付的完整资金闭环,不能把“前端显示支付成功”当成到账依据。
一、支付前提
需要准备:
- 已完成认证的小程序主体
- 可用的微信支付商户号
- 小程序 AppID 与商户号绑定
- 商户 API 证书或商户私钥
- API v3 密钥
- 微信支付平台证书或平台公钥机制
- 公网 HTTPS 支付回调地址
- 退款和对账所需权限
所有密钥只进入服务端密钥管理系统。正式上线前应轮换现有 AppSecret,并区分开发、预发和生产环境。
二、下单流程
1. 服务端验证订单
服务端重新读取:
- 用户和订单所有权
- 文件预检状态
- 目标打印机状态
- 有效报价和价格版本
- 应付金额和币种
- 订单是否已支付或关闭
2. 创建商户单号
商户单号必须全局唯一且不包含敏感文件名。描述只写通用业务名称,例如“自助打印服务”。
3. 调用小程序/JSAPI 下单
服务端向微信支付提交 AppID、商户号、金额、商户单号、描述、通知地址和用户标识。微信返回预支付信息后,服务端生成小程序拉起支付所需参数。
4. 小程序拉起支付
小程序调用支付 API。用户取消、网络中断或前端收到成功,都只影响页面提示,不直接决定服务端最终支付状态。
三、支付回调
服务器收到通知后必须:
- 读取原始请求体和微信支付签名头。
- 校验时间戳和随机串。
- 使用平台证书或平台公钥验签。
- 使用 API v3 密钥解密通知资源。
- 校验商户号、AppID、商户单号和平台交易号。
- 比较通知金额、币种与服务端订单金额。
- 使用平台交易号和事件类型去重。
- 在数据库事务中更新支付、订单、打印任务和 outbox。
- 快速返回成功,耗时工作异步处理。
回调可能重复、延迟或短暂丢失,接口必须幂等。
四、主动查单补偿
出现以下情况时主动查询微信支付:
- 小程序提示成功但服务端没有回调
- 回调验签成功但数据库事务失败
- 订单长时间停在
processing - 用户进入订单页要求刷新
- 每日对账发现平台有交易但本地状态不一致
查单结果仍要经过金额和商户身份校验,并通过同一状态机推进订单。
五、支付成功后创建打印任务
支付状态更新为 succeeded、订单更新为 paid、创建唯一打印任务和写入 outbox 应在同一数据库事务完成。
如果队列投递失败,outbox worker 可以继续重试;如果支付回调再次到达,order_id 唯一约束保证不会生成第二条打印任务。
六、退款流程
可以自动退款的典型情况
- 支付成功后发现设备长期不可用,任务从未提交打印。
- 文件在打印前的第二次校验失败。
- 平台故障导致任务超过承诺时间,且确认未提交打印。
需要人工判断的情况
- Windows 队列接受任务后代理失去结果。
- 卡纸导致只输出部分页面。
- 用户声称内容、色彩或页数不正确。
- 同一订单疑似重复打印。
退款请求使用独立幂等键,记录退款原因、金额、操作者和证据。只有收到微信退款结果或主动查询确认后,才把本地状态改为 refunded。
七、每日对账
每天下载微信支付账单,并与本地数据逐笔核对:
- 商户订单号
- 微信支付交易号
- 支付金额和币种
- 退款单号和退款金额
- 手续费
- 交易状态和时间
差异分为:
- 微信成功、本地未成功。
- 本地成功、微信没有成功记录。
- 金额不一致。
- 微信已退款、本地未完成退款。
- 本地标记退款、微信退款失败。
任何金额不一致都按最高严重级别处理,暂停相关自动流程并保全日志。
八、支付安全
- AppSecret、API v3 密钥和商户私钥不得出现在仓库、前端、聊天截图或文档正文。
- 不在命令行参数中传递私钥。
- 回调地址只接受 HTTPS。
- 验签失败、商户号不符或金额不一致一律拒绝。
- 支付接口限速,防止恶意创建大量商户单。
- 管理后台退款需要角色权限、二次确认和审计。
- 密钥定期轮换,泄露时可以快速吊销。
- 生产与测试商户配置隔离。
九、上线验收
- 0.01 元或小额真实支付成功
- 用户取消支付不会生成打印任务
- 重复回调不会重复打印
- 回调丢失后主动查单可以恢复
- 金额被篡改时服务端拒绝
- 全额退款成功并可查
- 退款回调重复仍保持幂等
- 当日账单与订单、退款和手续费一致
- 支付相关告警可以触达财务和技术负责人
支付、退款和对账没有全部通过之前,系统只能作为受控试用,不能标记为正式无人值守收费服务。
实现时以微信支付官方最新文档为准:商户接入指引、小程序/JSAPI 下单。