支付三渠归一:策略模式在收银系统中的实战

支付三渠归一:策略模式在收银系统中的实战

老张最怕听到的一句话:“老板,钱到哪了?”
以前用别的收银系统,顾客扫了码,钱先进了系统公司的账户,T+3才到老张的卡。
老张问:“我的钱,为什么先到你们那?”

01 钱不过我们的手

龙讯POS最核心的设计原则——“非金融中转方”

顾客 ──微信支付──→ 商户微信支付账户(mch_id)
         ↑
    龙讯POS仅调用官方API
    (不碰钱、不碰资金流、不做资金归集)

顾客扫码付的钱,直接进了商户在微信/支付宝的商户账户。龙讯POS不经手、不持有、不转移任何资金。

02 三种支付方式,一个界面

现金收银

快捷金额(¥10/¥20/¥50/¥100/刚好)+ 累加按钮(+5/+10/+20/+50/+100),不需要键盘,不需要计算器。

扫码支付

选择渠道→扫付款码→3秒到账→语音播报。系统自动识别渠道:18位数字前缀1015是微信,2530是支付宝,62开头是银联。

混合支付

勾选"混合支付",四个渠道同时显示,分别输入金额,各行之和必须等于订单总额。

03 技术实现:策略模式 + 注册表模式

PaymentSDK 接口

type PaymentSDK interface {
    Pay(authCode string, amount decimal.Decimal, outTradeNo string) (*PayResult, error)
    Query(outTradeNo string, transactionID string) (*QueryResult, error)
    Refund(outTradeNo string, transactionID string, totalAmount decimal.Decimal, refundAmount decimal.Decimal) (*RefundResult, error)
    Cancel(outTradeNo string, transactionID string) (*CancelResult, error)
    VerifyNotify(params map[string]string) (*NotifyResult, error)
    GenerateOutTradeNo() string
    IsMockMode() bool
}

7个方法覆盖被扫支付全生命周期。三个渠道各自实现这个接口,调用方只需要知道渠道名。

Manager 注册表

type Manager struct {
    mu       sync.RWMutex
    wechat   PaymentSDK
    alipay   PaymentSDK
    unionpay PaymentSDK
    mockMode bool
}

通过 sync.RWMutex 保护并发读取。新增渠道只需实现 PaymentSDK 接口并注册到 Manager

04 扫码支付核心流程

  1. LockOrder 加锁,防止并发操作
  2. 校验订单状态(必须为pending)
  3. 自动识别渠道或使用指定渠道
  4. 预创建payment记录(status=pending)
  5. 调用SDK.Pay()执行扣款
  6. 成功 → 3次事务重试更新payment+order
  7. 事务3次均失败 → 自动调用SDK.Cancel()撤销
  8. 撤销也失败 → 标记"需人工处理"

事务重试:指数退避

200ms → 400ms → 600ms,3次重试。全部失败则自动撤销支付,防止"钱扣了但订单没更新"。

05 混合支付:分步执行 + 自动回滚

逐渠道执行支付,任一渠道失败则回滚已完成的渠道:

  • 现金渠道:无法自动回滚,标记 rollback_pending
  • 电子渠道:先尝试Cancel(撤销),失败则Refund(退款)
  • 退款也失败:标记 rollback_pending(需人工介入)

06 支付回调:双检锁 + 金额校验

  1. 签名验证(伪造回调直接拒绝)
  2. 加锁 + 双检锁(已处理的记录做幂等处理)
  3. 金额校验(回调金额必须与记录金额一致)
  4. 支付宝额外二次主动查询确认
  5. 更新payment+order(3次事务重试)

07 没有公网IP?主动轮询

客户端每5秒查询一次支付状态,最多12次(共60秒)。不需要回调URL,不需要公网IP。

08 模拟模式

PAYMENT_MOCK_MODE=true(默认开启),所有渠道使用MockSDK,支付立即成功。填入真实密钥后关闭模拟模式,零切换成本。

09 总结

设计模式 应用场景
策略模式 PaymentSDK接口统一三渠道差异
注册表模式 Manager持有SDK实例,按渠道分发
双检锁 支付回调的幂等处理
事务重试 支付确认的3次指数退避
自动回滚 混合支付失败时的分步撤销

三个渠道,一个接口,一套逻辑。钱直接进你的账户,我们只是帮你调了一下API。


下期预告:《退款不翻车:从两步确认到自动回滚的工程实践》